diff --git a/CHANGELOG b/CHANGELOG index 7ea34044..2019cf3b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,39 @@ +Changes to version 0.8.2 +------------------------ +- Client: Added adjustable timeout to connect functions +- Client: Support for T selectors with different size than two bytes +- GOOSE publisher: added support for explicit GoID +- GOOSE subscriber: refactored subscriber +- Server: Added support for setting groups +- Server: Added support for data references in reports +- SCL parser: support for "Val" attributes in DA type definitions +- Server: Added function to disable all GOOSE publishing +- Client/Server: added helper functions for Dbpos +- C# API: more features and improved stability + +Changes to version 0.8.1 +------------------------ +- IEC 61850/MMS client: IedConnection and MmsConnection objects can now be reused +- reorganization of library header files +- C# API provides support for bit string and octet string data type +- IEC 61850 client/server: Added support for CommandTermination- +- C# API added handler for CommandTermination messages +- IEC 61850 server: IED name for static device model can now be configured at runtime +- Client/server: Fixed problem with association specific data sets +- GOOSE: fixed triggering GOOSE reports for data set members without trigger condition set +- Linux/Windows/BSD: added support for select based socket read (reduces CPU load) +- C# API added support for file services +- a lot of small bug fixes + +Changes to version 0.8 +----------------------- +- HAL: socket layer. Some changes. read and accept are now non-blocking. Changes the standard implementations (Linux/POSIX, WIN32, BSD) accordingly +- server stack: added single-threaded and threadless operation modes to better fit to resource constraint devices (added new configuration option CONFIG_MMS_SINGLE_THREADED) +- some small changes in server side control model handling (ControlHandler return values and behaviour) to enable threadless and single-threaded operation. +- C# client API extended and XML documentation completed +- some smaller bug fixes and extensions + + Changes to version 0.7.8 ------------------------ - IED client: added client side support for Ed.1 compliant control (client side automatically detects if a control is ed1 or ed2 compliant) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bcab8ee..4c597cc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ endif() project(libiec61850) set(LIB_VERSION_MAJOR "0") -set(LIB_VERSION_MINOR "7") -set(LIB_VERSION_PATCH "8") +set(LIB_VERSION_MINOR "8") +set(LIB_VERSION_PATCH "2") # feature checks include(CheckLibraryExists) @@ -26,6 +26,9 @@ set(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 CACHE STRING "Configure the maximum option(BUILD_EXAMPLES "Build the examples" ON) +option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" OFF) +option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF) + # choose the library features which shall be included option(CONFIG_INCLUDE_GOOSE_SUPPORT "Build with GOOSE support" ON) @@ -33,12 +36,15 @@ option(CONFIG_IEC61850_CONTROL_SERVICE "Build with support for IEC 61850 control option(CONFIG_IEC61850_REPORT_SERVICE "Build with support for IEC 61850 reporting services" ON) +option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON) + option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON) set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "8000" CACHE STRING "Default buffer size for buffered reports in byte" ) # advanced options option(DEBUG "Enable debugging mode (include assertions)" OFF) +option(DEBUG_SOCKET "Enable printf debugging for socket layer" OFF) option(DEBUG_COTP "Enable COTP printf debugging" OFF) option(DEBUG_ISO_SERVER "Enable ISO SERVER printf debugging" OFF) option(DEBUG_ISO_CLIENT "Enable ISO CLIENT printf debugging" OFF) @@ -51,64 +57,45 @@ option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" OFF) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/config - src/common + src/common/inc src/goose - src/hal - src/hal/ethernet - src/hal/socket - src/hal/thread - src/hal/filesystem - src/hal/time - src/iedclient - src/iedcommon - src/iedserver - src/iedserver/impl - src/iedserver/mms_mapping - src/iedserver/model - src/mms/asn1 - src/mms/iso_acse - src/mms/iso_client - src/mms/iso_cotp + src/hal/inc + src/iec61850/inc + src/iec61850/inc_private + src/mms/inc + src/mms/inc_private src/mms/iso_mms/asn1c - src/mms/iso_mms/client - src/mms/iso_mms/common - src/mms/iso_mms/server - src/mms/iso_presentation - src/mms/iso_server - src/mms/iso_common - src/mms/iso_session ) set(API_HEADERS - src/hal/time/time_hal.h - src/hal/ethernet/ethernet.h - src/hal/thread/thread.h - src/hal/filesystem/filesystem.h - src/common/libiec61850_common_api.h - src/common/linked_list.h - src/common/byte_buffer.h - src/iedclient/iec61850_client.h - src/iedcommon/iec61850_common.h - src/iedserver/iec61850_server.h - src/iedserver/model/model.h - src/iedserver/model/cdc.h - src/iedserver/model/dynamic_model.h - src/iedserver/model/config_file_parser.h - src/mms/iso_mms/common/mms_value.h - src/mms/iso_mms/common/mms_common.h - src/mms/iso_mms/common/mms_types.h - src/mms/iso_mms/server/mms_device_model.h - src/mms/iso_mms/server/mms_server.h - src/mms/iso_mms/server/mms_named_variable_list.h - src/mms/iso_mms/common/mms_type_spec.h - src/mms/asn1/ber_integer.h - src/mms/asn1/asn1_ber_primitive_value.h - src/mms/iso_server/iso_server.h - src/mms/iso_common/iso_connection_parameters.h + src/hal/inc/hal_time.h + src/hal/inc/hal_thread.h + src/hal/inc/hal_filesystem.h + src/common/inc/libiec61850_common_api.h + src/common/inc/linked_list.h + src/common/inc/byte_buffer.h + src/common/inc/lib_memory.h + src/iec61850/inc/iec61850_client.h + src/iec61850/inc/iec61850_common.h + src/iec61850/inc/iec61850_server.h + src/iec61850/inc/iec61850_model.h + src/iec61850/inc/iec61850_cdc.h + src/iec61850/inc/iec61850_dynamic_model.h + src/iec61850/inc/iec61850_config_file_parser.h + src/mms/inc/mms_value.h + src/mms/inc/mms_common.h + src/mms/inc/mms_types.h + src/mms/inc/mms_device_model.h + src/mms/inc/mms_server.h + src/mms/inc/mms_named_variable_list.h + src/mms/inc/mms_type_spec.h + src/mms/inc/mms_client_connection.h + src/mms/inc/iso_connection_parameters.h + src/mms/inc/iso_server.h + src/mms/inc/ber_integer.h + src/mms/inc/asn1_ber_primitive_value.h src/goose/goose_subscriber.h - src/mms/iso_mms/client/mms_client_connection.h - src/mms/iso_client/iso_client_connection.h - src/hal/socket/socket.h + src/goose/goose_receiver.h ) IF(WIN32) @@ -129,3 +116,30 @@ add_subdirectory(src) INSTALL(FILES ${API_HEADERS} DESTINATION include/libiec61850) +IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") +INCLUDE(InstallRequiredSystemLibraries) + +SET(CPACK_SET_DESTDIR "on") +SET(CPACK_INSTALL_PREFIX "/usr") +SET(CPACK_GENERATOR "DEB") + +SET(CPACK_PACKAGE_DESCRIPTION "IEC 61850 MMS/GOOSE client and server library") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IEC 61850 MMS/GOOSE client and server library") +SET(CPACK_PACKAGE_VENDOR "The libIEC61850 project") +SET(CPACK_PACKAGE_CONTACT "info@libiec61850.com") +SET(CPACK_PACKAGE_VERSION_MAJOR "${LIB_VERSION_MAJOR}") +SET(CPACK_PACKAGE_VERSION_MINOR "${LIB_VERSION_MINOR}") +SET(CPACK_PACKAGE_VERSION_PATCH "${LIB_VERSION_PATCH}") +SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CMAKE_SYSTEM_PROCESSOR}") +SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + +SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") +SET(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) + +SET(CPACK_COMPONENTS_ALL Libraries ApplicationData) +INCLUDE(CPack) + +ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") + + + diff --git a/Makefile b/Makefile index 0369ec80..3fd46ac3 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ LIB_SOURCE_DIRS += src/mms/asn1 LIB_SOURCE_DIRS += src/mms/iso_cotp LIB_SOURCE_DIRS += src/mms/iso_mms/server LIB_SOURCE_DIRS += src/mms/iso_mms/client -LIB_SOURCE_DIRS += src/mms/iso_client/impl +LIB_SOURCE_DIRS += src/mms/iso_client LIB_SOURCE_DIRS += src/mms/iso_common LIB_SOURCE_DIRS += src/mms/iso_mms/common LIB_SOURCE_DIRS += src/mms/iso_mms/asn1c @@ -20,13 +20,12 @@ LIB_SOURCE_DIRS += src/mms/iso_server ifndef EXCLUDE_ETHERNET_WINDOWS LIB_SOURCE_DIRS += src/goose endif -LIB_SOURCE_DIRS += src/iedclient/impl -LIB_SOURCE_DIRS += src/iedcommon -LIB_SOURCE_DIRS += src/iedserver -LIB_SOURCE_DIRS += src/iedserver/model -LIB_SOURCE_DIRS += src/iedserver/mms_mapping -LIB_SOURCE_DIRS += src/iedserver/impl -LIB_SOURCE_DIRS += src/hal +LIB_SOURCE_DIRS += src/iec61850/client +LIB_SOURCE_DIRS += src/iec61850/common +LIB_SOURCE_DIRS += src/iec61850/server +LIB_SOURCE_DIRS += src/iec61850/server/model +LIB_SOURCE_DIRS += src/iec61850/server/mms_mapping +LIB_SOURCE_DIRS += src/iec61850/server/impl ifeq ($(HAL_IMPL), WIN32) LIB_SOURCE_DIRS += src/hal/socket/win32 LIB_SOURCE_DIRS += src/hal/thread/win32 @@ -46,34 +45,15 @@ LIB_SOURCE_DIRS += src/hal/ethernet/bsd LIB_SOURCE_DIRS += src/hal/filesystem/linux LIB_SOURCE_DIRS += src/hal/time/unix endif - -LIB_INCLUDE_DIRS += src/mms/iso_presentation -LIB_INCLUDE_DIRS += src/mms/iso_session -LIB_INCLUDE_DIRS += src/mms/iso_cotp -LIB_INCLUDE_DIRS += src/mms/iso_acse LIB_INCLUDE_DIRS += config -LIB_INCLUDE_DIRS += src/mms/asn1 -LIB_INCLUDE_DIRS += src/mms/iso_client -LIB_INCLUDE_DIRS += src/mms/iso_mms/server -LIB_INCLUDE_DIRS += src/mms/iso_mms/common -LIB_INCLUDE_DIRS += src/mms/iso_mms/client -LIB_INCLUDE_DIRS += src/mms/iso_mms/asn1c -LIB_INCLUDE_DIRS += src/common -LIB_INCLUDE_DIRS += src/hal/socket -LIB_INCLUDE_DIRS += src/hal/thread -LIB_INCLUDE_DIRS += src/hal/ethernet -LIB_INCLUDE_DIRS += src/hal/filesystem -LIB_INCLUDE_DIRS += src/hal/time -LIB_INCLUDE_DIRS += src/hal +LIB_INCLUDE_DIRS += src/common/inc +LIB_INCLUDE_DIRS += src/mms/iso_mms/asn1c +LIB_INCLUDE_DIRS += src/mms/inc +LIB_INCLUDE_DIRS += src/mms/inc_private +LIB_INCLUDE_DIRS += src/hal/inc LIB_INCLUDE_DIRS += src/goose -LIB_INCLUDE_DIRS += src/mms/iso_server -LIB_INCLUDE_DIRS += src/mms/iso_common -LIB_INCLUDE_DIRS += src/iedclient -LIB_INCLUDE_DIRS += src/iedcommon -LIB_INCLUDE_DIRS += src/iedserver -LIB_INCLUDE_DIRS += src/iedserver/model -LIB_INCLUDE_DIRS += src/iedserver/mms_mapping -LIB_INCLUDE_DIRS += src/iedserver/impl +LIB_INCLUDE_DIRS += src/iec61850/inc +LIB_INCLUDE_DIRS += src/iec61850/inc_private ifeq ($(HAL_IMPL), WIN32) LIB_INCLUDE_DIRS += third_party/winpcap/Include endif @@ -84,35 +64,34 @@ ifndef INSTALL_PREFIX INSTALL_PREFIX = ./.install endif -LIB_API_HEADER_FILES = src/hal/time/time_hal.h -LIB_API_HEADER_FILES += src/hal/ethernet/ethernet.h -LIB_API_HEADER_FILES += src/hal/thread/thread.h -LIB_API_HEADER_FILES += src/hal/filesystem/filesystem.h -LIB_API_HEADER_FILES += src/common/libiec61850_common_api.h -LIB_API_HEADER_FILES += src/common/linked_list.h -LIB_API_HEADER_FILES += src/common/byte_buffer.h -LIB_API_HEADER_FILES += src/iedclient/iec61850_client.h -LIB_API_HEADER_FILES += src/iedcommon/iec61850_common.h -LIB_API_HEADER_FILES += src/iedserver/iec61850_server.h -LIB_API_HEADER_FILES += src/iedserver/model/model.h -LIB_API_HEADER_FILES += src/iedserver/model/cdc.h -LIB_API_HEADER_FILES += src/iedserver/model/dynamic_model.h -LIB_API_HEADER_FILES += src/iedserver/model/config_file_parser.h -LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_value.h -LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_common.h -LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_types.h -LIB_API_HEADER_FILES += src/mms/iso_mms/server/mms_device_model.h -LIB_API_HEADER_FILES += src/mms/iso_mms/server/mms_server.h -LIB_API_HEADER_FILES += src/mms/iso_mms/server/mms_named_variable_list.h -LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_type_spec.h -LIB_API_HEADER_FILES += src/mms/asn1/ber_integer.h -LIB_API_HEADER_FILES += src/mms/asn1/asn1_ber_primitive_value.h -LIB_API_HEADER_FILES += src/mms/iso_server/iso_server.h -LIB_API_HEADER_FILES += src/mms/iso_common/iso_connection_parameters.h +LIB_API_HEADER_FILES = src/hal/inc/hal_time.h +LIB_API_HEADER_FILES += src/hal/inc/hal_thread.h +LIB_API_HEADER_FILES += src/hal/inc/hal_filesystem.h +LIB_API_HEADER_FILES += src/common/inc/libiec61850_common_api.h +LIB_API_HEADER_FILES += src/common/inc/linked_list.h +LIB_API_HEADER_FILES += src/common/inc/byte_buffer.h +LIB_API_HEADER_FILES += src/common/inc/lib_memory.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_client.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_common.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_server.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_model.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_cdc.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_dynamic_model.h +LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_config_file_parser.h +LIB_API_HEADER_FILES += src/mms/inc/mms_value.h +LIB_API_HEADER_FILES += src/mms/inc/mms_common.h +LIB_API_HEADER_FILES += src/mms/inc/mms_types.h +LIB_API_HEADER_FILES += src/mms/inc/mms_device_model.h +LIB_API_HEADER_FILES += src/mms/inc/mms_server.h +LIB_API_HEADER_FILES += src/mms/inc/mms_named_variable_list.h +LIB_API_HEADER_FILES += src/mms/inc/mms_type_spec.h +LIB_API_HEADER_FILES += src/mms/inc/mms_client_connection.h +LIB_API_HEADER_FILES += src/mms/inc/iso_connection_parameters.h +LIB_API_HEADER_FILES += src/mms/inc/iso_server.h +LIB_API_HEADER_FILES += src/mms/inc/ber_integer.h +LIB_API_HEADER_FILES += src/mms/inc/asn1_ber_primitive_value.h LIB_API_HEADER_FILES += src/goose/goose_subscriber.h -LIB_API_HEADER_FILES += src/mms/iso_mms/client/mms_client_connection.h -LIB_API_HEADER_FILES += src/mms/iso_client/iso_client_connection.h -LIB_API_HEADER_FILES += src/hal/socket/socket.h +LIB_API_HEADER_FILES += src/goose/goose_receiver.h get_sources_from_directory = $(wildcard $1/*.c) get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir))) diff --git a/config/stack_config.h b/config/stack_config.h index 1c38acbb..e995ab0d 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -10,9 +10,10 @@ #define STACK_CONFIG_H_ /* include asserts if set to 1 */ -#define DEBUG 0 +#define DEBUG 1 /* print debugging information with printf if set to 1 */ +#define DEBUG_SOCKET 0 #define DEBUG_COTP 0 #define DEBUG_ISO_SERVER 0 #define DEBUG_ISO_CLIENT 0 @@ -20,10 +21,28 @@ #define DEBUG_IED_CLIENT 0 #define DEBUG_MMS_CLIENT 0 #define DEBUG_MMS_SERVER 0 +#define DEBUG_GOOSE_SUBSCRIBER 0 +#define DEBUG_GOOSE_PUBLISHER 0 /* Maximum MMS PDU SIZE - default is 65000 */ #define CONFIG_MMS_MAXIMUM_PDU_SIZE 65000 +/* + * Enable single threaded mode + * + * 1 ==> server runs in single threaded mode (a single thread for the server and all client connections) + * 0 ==> server runs in multi-threaded mode (one thread for each connection and + * one server background thread ) + */ +#define CONFIG_MMS_SINGLE_THREADED 1 + +/* + * Optimize stack for threadless operation - don't use semaphores + * + * WARNING: If set to 1 normal single- and multi-threaded server are no longer working! + */ +#define CONFIG_MMS_THREADLESS_STACK 0 + /* number of concurrent MMS client connections the server accepts, -1 for no limit */ #define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 @@ -48,6 +67,7 @@ /* Ethernet interface ID for GOOSE and SV */ #define CONFIG_ETHERNET_INTERFACE_ID "eth0" //#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" +//#define CONFIG_ETHERNET_INTERFACE_ID "eth-f" //#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. /* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */ @@ -102,10 +122,16 @@ /* The default buffer size of buffered RCBs in bytes */ #define CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE 65536 +/* include support for setting groups */ +#define CONFIG_IEC61850_SETTING_GROUPS 1 + +/* default reservation time of a setting group control block in s */ +#define CONFIG_IEC61850_SG_RESVTMS 10 + /* default results for MMS identify service */ #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" -#define CONFIG_DEFAULT_MMS_REVISION "0.7.8" +#define CONFIG_DEFAULT_MMS_REVISION "0.8.2" /* MMS virtual file store base path - where file services are looking for files */ #define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/" @@ -113,6 +139,12 @@ /* Maximum number of open file per MMS connection (for MMS file read service) */ #define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5 +#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10 + +#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10 + +#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10 + /* Definition of supported services */ #define MMS_DEFAULT_PROFILE 1 @@ -140,4 +172,6 @@ /* VMD scope named variables are not used by IEC 61850 */ #define CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES 0 +#define CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS 0 + #endif /* STACK_CONFIG_H_ */ diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake index 249d8f24..3f46e272 100644 --- a/config/stack_config.h.cmake +++ b/config/stack_config.h.cmake @@ -19,6 +19,7 @@ #cmakedefine01 DEBUG /* print debugging information with printf if set to 1 */ +#cmakedefine01 DEBUG_SOCKET #cmakedefine01 DEBUG_COTP #cmakedefine01 DEBUG_ISO_SERVER #cmakedefine01 DEBUG_ISO_CLIENT @@ -26,6 +27,17 @@ #cmakedefine01 DEBUG_IED_CLIENT #cmakedefine01 DEBUG_MMS_CLIENT #cmakedefine01 DEBUG_MMS_SERVER +#cmakedefine01 DEBUG_GOOSE_SUBSCRIBER +#cmakedefine01 DEBUG_GOOSE_PUBLISHER + +/* 1 ==> server runs in single threaded mode (one dedicated thread for the server) + * 0 ==> server runs in multi threaded mode (one thread for each connection and + * one server background thread ) + */ +#cmakedefine01 CONFIG_MMS_SINGLE_THREADED + +/* Optimize stack for threadless operation - don't use semaphores */ +#cmakedefine01 CONFIG_MMS_THREADLESS_STACK /* Maximum MMS PDU SIZE - default is 65000 */ #cmakedefine CONFIG_MMS_MAXIMUM_PDU_SIZE @CONFIG_MMS_MAXIMUM_PDU_SIZE@ @@ -52,9 +64,9 @@ #define CONFIG_TCP_READ_TIMEOUT_MS 1000 /* Ethernet interface ID for GOOSE and SV */ -//#define CONFIG_ETHERNET_INTERFACE_ID "eth0" +#define CONFIG_ETHERNET_INTERFACE_ID "eth0" //#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" -#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. +//#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names. /* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */ #cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT @@ -108,6 +120,12 @@ /* The default buffer size of buffered RCBs in bytes */ #cmakedefine CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE @CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE@ +/* include support for setting groups */ +#cmakedefine01 CONFIG_IEC61850_SETTING_GROUPS + +/* default reservation time of a setting group control block in s */ +#define CONFIG_IEC61850_SG_RESVTMS 100 + /* default results for MMS identify service */ #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" @@ -125,6 +143,12 @@ /* Maximum number of open file per MMS connection (for MMS file read service) */ #define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5 +#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10 + +#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10 + +#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10 + /* Definition of supported services */ #define MMS_DEFAULT_PROFILE 1 diff --git a/demos/beaglebone/static_model.c b/demos/beaglebone/static_model.c index 0150f871..5c8824c5 100644 --- a/demos/beaglebone/static_model.c +++ b/demos/beaglebone/static_model.c @@ -150,15 +150,12 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal; extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q; extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; -extern DataSet ds_GenericIO_LLN0_Events; +static DataSetEntry ds_GenericIO_LLN0_Events_fcda0; +static DataSetEntry ds_GenericIO_LLN0_Events_fcda1; +static DataSetEntry ds_GenericIO_LLN0_Events_fcda2; +static DataSetEntry ds_GenericIO_LLN0_Events_fcda3; - -extern DataSetEntry ds_GenericIO_LLN0_Events_fcda0; -extern DataSetEntry ds_GenericIO_LLN0_Events_fcda1; -extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; -extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; - -DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { +static DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { "beagleGenericIO", "GGIO1$ST$SPCSO1$stVal", -1, @@ -167,7 +164,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { &ds_GenericIO_LLN0_Events_fcda1 }; -DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { +static DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { "beagleGenericIO", "GGIO1$ST$SPCSO2$stVal", -1, @@ -176,7 +173,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { &ds_GenericIO_LLN0_Events_fcda2 }; -DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { +static DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { "beagleGenericIO", "GGIO1$ST$SPCSO3$stVal", -1, @@ -185,7 +182,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { &ds_GenericIO_LLN0_Events_fcda3 }; -DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { +static DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { "beagleGenericIO", "GGIO1$ST$DPCSO1$stVal", -1, @@ -194,12 +191,11 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { NULL }; -DataSet ds_GenericIO_LLN0_Events = { +static DataSet ds_GenericIO_LLN0_Events = { "beagleGenericIO", "LLN0$Events", 4, - &ds_GenericIO_LLN0_Events_fcda0, - NULL + &ds_GenericIO_LLN0_Events_fcda0 }; LogicalDevice iedModel_GenericIO = { @@ -1923,11 +1919,22 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { NULL, 0}; -extern ReportControlBlock iedModel_GenericIO_LLN0_report0; -extern ReportControlBlock iedModel_GenericIO_LLN0_report1; -ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; -ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCB201", "Events2", false, "Events", 1, 8, 111, 50, 1000, NULL}; +static ReportControlBlock iedModel_GenericIO_LLN0_report0; +static ReportControlBlock iedModel_GenericIO_LLN0_report1; + +static ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events1", false, "Events", 1, 16, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; +static ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCB2", "Events2", false, "Events", 1, 16, 111, 50, 1000, NULL}; + + + + + + + + + + diff --git a/dotnet/IEC61850forCSharp/Control.cs b/dotnet/IEC61850forCSharp/Control.cs index 0b3294bc..d064334b 100644 --- a/dotnet/IEC61850forCSharp/Control.cs +++ b/dotnet/IEC61850forCSharp/Control.cs @@ -29,8 +29,14 @@ using IEC61850.Common; namespace IEC61850 { + /// + /// IEC 61850 common API parts (used by client and server API) + /// namespace Common { + /// + /// Control model + /// public enum ControlModel { CONTROL_MODEL_STATUS_ONLY = 0, CONTROL_MODEL_DIRECT_NORMAL = 1, @@ -38,39 +44,142 @@ namespace IEC61850 CONTROL_MODEL_DIRECT_ENHANCED = 3, CONTROL_MODEL_SBO_ENHANCED = 4 } + + /// + /// Originator category + /// + public enum OrCat { + /** Not supported - should not be used */ + NOT_SUPPORTED = 0, + /** Control operation issued from an operator using a client located at bay level */ + BAY_CONTROL = 1, + /** Control operation issued from an operator using a client located at station level */ + STATION_CONTROL = 2, + /** Control operation from a remote operator outside the substation (for example network control center) */ + REMOTE_CONTROL = 3, + /** Control operation issued from an automatic function at bay level */ + AUTOMATIC_BAY = 4, + /** Control operation issued from an automatic function at station level */ + AUTOMATIC_STATION = 5, + /** Control operation issued from a automatic function outside of the substation */ + AUTOMATIC_REMOTE = 6, + /** Control operation issued from a maintenance/service tool */ + MAINTENANCE = 7, + /** Status change occurred without control action (for example external trip of a circuit breaker or failure inside the breaker) */ + PROCESS = 8 + } } namespace Client { + [StructLayout(LayoutKind.Sequential)] + internal struct LastApplErrorInternal + { + public int ctlNum; + public int error; + public int addCause; + } + + public class LastApplError + { + public int ctlNum; + public int error; + public ControlAddCause addCause; + + + internal LastApplError (LastApplErrorInternal lastApplError) + { + this.addCause = (ControlAddCause) lastApplError.addCause; + this.error = lastApplError.error; + this.ctlNum = lastApplError.ctlNum; + } + } + + /// + /// Control object. + /// public class ControlObject { + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr ControlObjectClient_create(string objectReference, IntPtr connection); + private static extern LastApplErrorInternal ControlObjectClient_getLastApplError(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void ControlObjectClient_destroy(IntPtr self); + private static extern IntPtr ControlObjectClient_create(string objectReference, IntPtr connection); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern int ControlObjectClient_getControlModel(IntPtr self); + private static extern void ControlObjectClient_destroy(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime); + private static extern int ControlObjectClient_getControlModel(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern bool ControlObjectClient_select(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern bool ControlObjectClient_selectWithValue(IntPtr self, IntPtr ctlVal); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern bool ControlObjectClient_cancel(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_setOrigin(IntPtr self, string orIdent, int orCat); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_enableInterlockCheck(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_enableSynchroCheck(IntPtr self); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void InternalCommandTerminationHandler(IntPtr parameter,IntPtr controlClient); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void ControlObjectClient_setCommandTerminationHandler(IntPtr self, + InternalCommandTerminationHandler handler, IntPtr handlerParameter); + + public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject); private IntPtr controlObject; + private CommandTerminationHandler commandTerminationHandler = null; + private Object commandTerminationHandlerParameter = null; + + private void MyCommandTerminationHandler (IntPtr paramter, IntPtr controlClient) + { + if (commandTerminationHandler != null) + commandTerminationHandler(commandTerminationHandlerParameter, this); + } + + internal ControlObject (string objectReference, IntPtr connection) { this.controlObject = ControlObjectClient_create(objectReference, connection); if (this.controlObject == System.IntPtr.Zero) throw new IedConnectionException("Control object not found", 0); + + InternalCommandTerminationHandler intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler); + + ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject); } ~ControlObject () { - ControlObjectClient_destroy(controlObject); + if (this.controlObject != System.IntPtr.Zero) + ControlObjectClient_destroy(controlObject); } + /// + /// Gets the control model. + /// + /// + /// The control model. + /// public ControlModel GetControlModel () { ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(controlObject); @@ -78,11 +187,36 @@ namespace IEC61850 return controlModel; } + /// + /// Sets the origin parameter used by control commands. + /// + /// + /// Originator. An arbitrary string identifying the controlling client. + /// + /// + /// Originator category. + /// + public void SetOrigin (string originator, OrCat originatorCategory) + { + ControlObjectClient_setOrigin(controlObject, originator, (int) originatorCategory); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise public bool Operate (bool ctlVal) { return Operate (ctlVal, 0); } + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise public bool Operate (bool ctlVal, UInt64 operTime) { MmsValue value = new MmsValue(ctlVal); @@ -90,11 +224,22 @@ namespace IEC61850 return Operate (value, operTime); } + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise public bool Operate (float ctlVal) { return Operate (ctlVal, 0); } + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise public bool Operate (float ctlVal, UInt64 operTime) { MmsValue value = new MmsValue(ctlVal); @@ -102,11 +247,22 @@ namespace IEC61850 return Operate (value, operTime); } + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise public bool Operate (int ctlVal) { return Operate (ctlVal, 0); } + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise public bool Operate (int ctlVal, UInt64 operTime) { MmsValue value = new MmsValue(ctlVal); @@ -114,15 +270,138 @@ namespace IEC61850 return Operate (value, operTime); } + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// true when the operation has been successful, false otherwise public bool Operate (MmsValue ctlVal) { return Operate (ctlVal, 0); } + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// true when the operation has been successful, false otherwise public bool Operate (MmsValue ctlVal, UInt64 operTime) { return ControlObjectClient_operate(controlObject, ctlVal.valueReference, operTime); } + + /// + /// Select the control object. + /// + /// true when the selection has been successful, false otherwise + public bool Select () + { + return ControlObjectClient_select(controlObject); + } + + + /// + /// Send a select with value command for generic MmsValue instances + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (MmsValue ctlVal) + { + return ControlObjectClient_selectWithValue(controlObject, ctlVal.valueReference); + } + + /// + /// Send a select with value command for boolean controls + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (bool ctlVal) + { + return SelectWithValue(new MmsValue(ctlVal)); + } + + /// + /// Send a select with value command for integer controls + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (int ctlVal) + { + return SelectWithValue(new MmsValue(ctlVal)); + } + + /// + /// Send a select with value command for float controls + /// + /// + /// the value to be checked. + /// + /// true when the selection has been successful, false otherwise + public bool SelectWithValue (float ctlVal) + { + return SelectWithValue(new MmsValue(ctlVal)); + } + + /// + /// Cancel a selection or time activated operation + /// + /// true when the cancelation has been successful, false otherwise + public bool Cancel () + { + return ControlObjectClient_cancel(controlObject); + } + + /// + /// Enables the synchro check for operate commands + /// + public void EnableSynchroCheck () + { + ControlObjectClient_enableSynchroCheck(controlObject); + } + + /// + /// Enables the interlock check for operate and select commands + /// + public void EnableInterlockCheck () + { + ControlObjectClient_enableInterlockCheck(controlObject); + } + + /// + /// Gets the last received LastApplError (Additional Cause Diagnostics) value. + /// + /// + /// The last appl error. + /// + public LastApplError GetLastApplError () + { + LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(controlObject); + + return new LastApplError(lastApplError); + } + + /// + /// Sets the command termination handler. + /// + /// + /// the handler (delegate) that is invoked when a CommandTerminationMessage is received. + /// + /// + /// Parameter. + /// + public void SetCommandTerminationHandler (CommandTerminationHandler handler, Object parameter) + { + this.commandTerminationHandler = handler; + this.commandTerminationHandlerParameter = parameter; + } + } } diff --git a/dotnet/IEC61850forCSharp/DataSet.cs b/dotnet/IEC61850forCSharp/DataSet.cs index 12ec8d60..c0c887e9 100644 --- a/dotnet/IEC61850forCSharp/DataSet.cs +++ b/dotnet/IEC61850forCSharp/DataSet.cs @@ -24,10 +24,16 @@ using System; using System.Runtime.InteropServices; +using IEC61850.Common; + namespace IEC61850 { namespace Client { + /// + /// This class is used to represent a data set. It is used to store the values + /// of a data set. + /// public class DataSet { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -51,6 +57,12 @@ namespace IEC61850 this.nativeObject = nativeObject; } + /// + /// Gets the object reference of the data set + /// + /// + /// object reference. + /// public string GetReference () { if (reference == null) { @@ -62,6 +74,15 @@ namespace IEC61850 return reference; } + /// + /// Gets the values associated with the data set object + /// + /// This function will return the locally stored values associated with the data set. + /// These are the values received by the last request to the server. A call to this method doesn't + /// invoke a request to the server! + /// + /// The locally stored values of the data set (as MmsValue instance of type MMS_ARRAY) + /// public MmsValue GetValues () { if (values == null) { @@ -73,6 +94,13 @@ namespace IEC61850 return values; } + + /// + /// Gets the number of elements of the data set + /// + /// + /// the number of elementes (data set members) + /// public int GetSize () { return ClientDataSet_getDataSetSize (nativeObject); diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 60bd7952..82f133a2 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -28,8 +28,14 @@ using System.Collections; using IEC61850.Common; +/// +/// IEC 61850 API for the libiec61850 .NET wrapper library +/// namespace IEC61850 { + /// + /// IEC 61850 client API. + /// namespace Client { @@ -67,6 +73,12 @@ namespace IEC61850 [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] static extern IntPtr IedConnection_create (); + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_destroy (IntPtr self); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_setConnectTimeout(IntPtr self, UInt32 timeoutInMs); + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] static extern void IedConnection_connect (IntPtr self, out int error, string hostname, int tcpPort); @@ -88,6 +100,9 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr IedConnection_getDataDirectory (IntPtr self, out int error, string dataReference); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataDirectoryByFC (IntPtr self, out int error, string dataReference, FunctionalConstraint fc); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr IedConnection_getDataDirectoryFC (IntPtr self, out int error, string dataReference); @@ -100,7 +115,10 @@ namespace IEC61850 [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] static extern IntPtr IedConnection_getLogicalDeviceDirectory (IntPtr self, out int error, string logicalDeviceName); - + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void InternalConnectionClosedHandler (IntPtr parameter,IntPtr Iedconnection); public delegate void ConnectionClosedHandler (IedConnection connection); @@ -124,7 +142,19 @@ namespace IEC61850 static extern IntPtr IedConnection_getMmsConnection (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection); + static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_deleteFile(IntPtr self, out int error, string fileName); + + /******************** + * FileDirectoryEntry + *********************/ + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void FileDirectoryEntry_destroy(IntPtr self); /**************** * LinkedList @@ -136,7 +166,16 @@ namespace IEC61850 static extern IntPtr LinkedList_getData (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void LinkedList_destroy (IntPtr self); + static extern void LinkedList_destroy (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroyStatic(IntPtr self); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void LinkedListValueDeleteFunction(IntPtr pointer); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr LinkedList_create (); @@ -144,7 +183,7 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void LinkedList_add (IntPtr self, IntPtr data); - private IntPtr connection; + private IntPtr connection = IntPtr.Zero; private InternalConnectionClosedHandler connectionClosedHandler; private ConnectionClosedHandler userProvidedHandler = null; @@ -153,6 +192,12 @@ namespace IEC61850 connection = IedConnection_create (); } + ~IedConnection () + { + if (connection != IntPtr.Zero) + IedConnection_destroy(connection); + } + public IsoConnectionParameters GetConnectionParameters () { IntPtr mmsConnection = IedConnection_getMmsConnection(connection); @@ -162,12 +207,32 @@ namespace IEC61850 return new IsoConnectionParameters(parameters); } + private void FreeHGlobaleDeleteFunction (IntPtr pointer) + { + Marshal.FreeHGlobal(pointer); + } + + + private UInt32 connectTimeout = 10000; + + public UInt32 ConnectTimeout { + get { + return connectTimeout; + } + set { + connectTimeout = value; + } + } + + /// Establish an MMS connection to a server /// This exception is thrown if there is a connection or service error public void Connect (string hostname, int tcpPort) { int error; + IedConnection_setConnectTimeout(connection, connectTimeout); + IedConnection_connect (connection, out error, hostname, tcpPort); if (error != 0) @@ -199,19 +264,41 @@ namespace IEC61850 if (error != 0) throw new IedConnectionException ("GetDeviceDirectory failed", error); - IntPtr element = LinkedList_getNext (linkedList); - List newList = new List (); - while (element != IntPtr.Zero) { - string ld = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + if (fileDirectory == false) { - newList.Add (ld); + IntPtr element = LinkedList_getNext (linkedList); - element = LinkedList_getNext (element); - } + while (element != IntPtr.Zero) { + string ld = Marshal.PtrToStringAnsi (LinkedList_getData (element)); - LinkedList_destroy (linkedList); + newList.Add (ld); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + } + else { + + IntPtr element = LinkedList_getNext(linkedList); + + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); + + FileDirectoryEntry entry = new FileDirectoryEntry(elementData); + + newList.Add(entry.GetFileName()); + + FileDirectoryEntry_destroy(elementData); + + element = LinkedList_getNext(element); + } + + LinkedList_destroyStatic(linkedList); + } return newList; } @@ -243,6 +330,12 @@ namespace IEC61850 return newList; } + /// Get the directory of a logical node (LN) + /// This function returns the directory contents of a LN. Depending on the provided ACSI class + /// The function returns either data object references, or references of other objects like data sets, + /// report control blocks, ... + /// The object reference of a DO, SDO, or DA. + /// the ACSI class of the requested directory elements. /// This exception is thrown if there is a connection or service error public List GetLogicalNodeDirectory (string logicalNodeName, ACSIClass acsiClass) { @@ -270,6 +363,8 @@ namespace IEC61850 return newList; } + /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA + /// The object reference of a DO, SDO, or DA. /// This exception is thrown if there is a connection or service error public List GetDataDirectory (string dataReference) { @@ -297,6 +392,40 @@ namespace IEC61850 return newList; } + /// Get the list of attributes with the specified FC of a DO, SDO, or DA + /// The object reference of a DO, SDO, or DA. + /// Functional constraint + /// This exception is thrown if there is a connection or service error + public List GetDataDirectory (string dataReference, FunctionalConstraint fc) + { + int error; + + IntPtr linkedList = IedConnection_getDataDirectoryByFC (connection, out error, dataReference, fc); + + if (error != 0) + throw new IedConnectionException ("GetDataDirectory failed", error); + + IntPtr element = LinkedList_getNext (linkedList); + + List newList = new List (); + + while (element != IntPtr.Zero) { + string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + + newList.Add (dataObject); + + element = LinkedList_getNext (element); + } + + LinkedList_destroy (linkedList); + + return newList; + } + + /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA + /// This function is similar to the GetDataDirectory except that the returned element names + /// have the functional contraint (FC) appended. + /// The object reference of a DO, SDO, or DA. /// This exception is thrown if there is a connection or service error public List GetDataDirectoryFC (string dataReference) { @@ -324,6 +453,23 @@ namespace IEC61850 return newList; } + + /// Read the variable specification (type description of a DA or FDCO + /// The object reference of a DA or FCDO. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public MmsVariableSpecification GetVariableSpecification (string objectReference, FunctionalConstraint fc) + { + int error; + + IntPtr varSpecPtr = IedConnection_getVariableSpecification(connection, out error, objectReference, (int) fc); + + if (error != 0) + throw new IedConnectionException ("GetVariableSpecification failed", error); + + return new MmsVariableSpecification(varSpecPtr, true); + } + private IntPtr readObjectInternal (string objectReference, FunctionalConstraint fc) { int error; @@ -342,6 +488,7 @@ namespace IEC61850 /// Read the value of a data attribute (DA) or functional constraint data object (FCDO). /// The object reference of a DA or FCDO. /// The functional constraint (FC) of the object + /// the received value as an MmsValue instance /// This exception is thrown if there is a connection or service error public MmsValue ReadValue (String objectReference, FunctionalConstraint fc) { @@ -353,6 +500,7 @@ namespace IEC61850 /// Read the value of a basic data attribute (BDA) of type boolean. /// The object reference of a BDA. /// The functional constraint (FC) of the object + /// the received boolean value /// This exception is thrown if there is a connection or service error public bool ReadBooleanValue (string objectReference, FunctionalConstraint fc) { @@ -423,6 +571,25 @@ namespace IEC61850 } } + /// Read the value of a basic data attribute (BDA) of type bit string. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public int ReadBitStringValue (string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternal (objectReference, fc); + + if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { + int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); + + MmsValue_delete (mmsValue); + return bitStringValue; + } else { + MmsValue_delete (mmsValue); + throw new IedConnectionException ("Result is not of type bit string", 0); + } + } + /// Read the value of a basic data attribute (BDA) of type timestamp (MMS_UTC_TIME). /// The object reference of a BDA. /// The functional constraint (FC) of the object @@ -457,6 +624,12 @@ namespace IEC61850 throw new IedConnectionException ("Result is not of type integer (MMS_INTEGER)", 0); } + /// Write the value of a data attribute (DA) or functional constraint data object (FCDO). + /// This function can be used to write simple or complex variables (setpoints, parameters, descriptive values...) + /// of the server. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// MmsValue object representing asimple or complex variable data /// This exception is thrown if there is a connection or service error public void WriteValue (string objectReference, FunctionalConstraint fc, MmsValue value) { @@ -466,8 +639,111 @@ namespace IEC61850 if (error != 0) throw new IedConnectionException ("Write value failed", error); - } - + } + + /// Read the content of a file directory. + /// The name of the directory. + /// This exception is thrown if there is a connection or service error + public List GetFileDirectory(string directoryName) + { + int error; + + IntPtr fileEntryList = IedConnection_getFileDirectory(connection, out error, directoryName); + + if (error != 0) + throw new IedConnectionException("Reading file directory failed", error); + + List fileDirectory = new List(); + + IntPtr element = LinkedList_getNext(fileEntryList); + + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); + + FileDirectoryEntry entry = new FileDirectoryEntry(elementData); + + fileDirectory.Add(entry); + + FileDirectoryEntry_destroy(elementData); + + element = LinkedList_getNext(element); + } + + LinkedList_destroyStatic(fileEntryList); + + return fileDirectory; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool InternalIedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead); + + private bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + GetFileCallback getFileCallback = (GetFileCallback) handle.Target; + + byte[] bytes = new byte[bytesRead]; + + Marshal.Copy(buffer, bytes, 0, (int) bytesRead); + + return getFileCallback.handler(getFileCallback.parameter, bytes); + } + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 IedConnection_getFile(IntPtr self, out int error, string fileName, InternalIedClientGetFileHandler handler, + IntPtr handlerParameter); + + + public delegate bool GetFileHandler(object parameter, byte[] data); + + private class GetFileCallback + { + public GetFileCallback(GetFileHandler handler, object parameter) + { + this.handler = handler; + this.parameter = parameter; + } + + public GetFileHandler handler; + public object parameter; + } + + /// + /// Download a file from the server. + /// + /// + /// File name of the file (full path) + /// + /// + /// Callback handler that is invoked for each chunk of the file received + /// + /// + /// User provided parameter that is passed to the callback handler + /// + public void GetFile(string fileName, GetFileHandler handler, object parameter) + { + int error; + + GetFileCallback getFileCallback = new GetFileCallback(handler, parameter); + + GCHandle handle = GCHandle.Alloc(getFileCallback); + + IedConnection_getFile(connection, out error, fileName, new InternalIedClientGetFileHandler(iedClientGetFileHandler), + GCHandle.ToIntPtr(handle)); + + if (error != 0) + throw new IedConnectionException("Error reading file", error); + + handle.Free(); + } + + /// + /// Abort (close) the connection. + /// + /// This function will send an abort request to the server. This will immediately interrupt the + /// connection. /// This exception is thrown if there is a connection or service error public void Abort () { @@ -479,6 +755,11 @@ namespace IEC61850 throw new IedConnectionException ("Abort failed", error); } + /// + /// Release (close) the connection. + /// + /// This function will send an release request to the server. The function will block until the + /// connection is released or an error occured. /// This exception is thrown if there is a connection or service error public void Release () { @@ -490,6 +771,12 @@ namespace IEC61850 throw new IedConnectionException ("Release failed", error); } + /// + /// Immediately close the connection. + /// + /// This function will close the connnection to the server by closing the TCP connection. + /// The client will not send an abort or release request as required by the specification! + /// This exception is thrown if there is a connection or service error public void Close () { IedConnection_close(connection); @@ -501,6 +788,14 @@ namespace IEC61850 userProvidedHandler (this); } + /// + /// Install a callback handler that will be invoked if the connection is closed. + /// + /// The handler is called when the connection is closed no matter if the connection was closed + /// by the client or by the server. Any new call to this function will replace the callback handler installed + /// by a prior function call. + /// The user provided callback handler + /// This exception is thrown if there is a connection or service error public void InstallConnectionClosedHandler (ConnectionClosedHandler handler) { connectionClosedHandler = new InternalConnectionClosedHandler (MyConnectionClosedHandler); @@ -510,6 +805,28 @@ namespace IEC61850 IedConnection_installConnectionClosedHandler (connection, connectionClosedHandler, connection); } + /// + /// Read the values of a data set (GetDataSetValues service). + /// + /// This function will invoke a readDataSetValues service and return a new DataSet value containing the + /// received values. + /// The object reference of the data set + + /// This exception is thrown if there is a connection or service error + public DataSet GetDataSetValues (string dataSetReference) + { + return ReadDataSetValues(dataSetReference, null); + } + + /// + /// Read the values of a data set (GetDataSetValues service). + /// + /// This function will invoke a readDataSetValues service and return a new DataSet value containing the + /// received values. If an existing instance of DataSet is provided to the function the existing instance will be + /// updated by the new values. + /// The object reference of the data set + /// The object reference of an existing data set instance or null + /// a DataSet instance containing the received values /// This exception is thrown if there is a connection or service error public DataSet ReadDataSetValues (string dataSetReference, DataSet dataSet) { @@ -531,6 +848,14 @@ namespace IEC61850 return dataSet; } + /// + /// Create a new data set. + /// + /// This function creates a new data set at the server. The data set consists of the members defined + /// by the list of object references provided. + /// The object reference of the data set + /// A list of object references of the data set elements + /// This exception is thrown if there is a connection or service error public void CreateDataSet (string dataSetReference, List dataSetElements) { IntPtr linkedList = LinkedList_create (); @@ -545,13 +870,20 @@ namespace IEC61850 IedConnection_createDataSet (connection, out error, dataSetReference, linkedList); - LinkedList_destroy (linkedList); + LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction)); if (error != 0) throw new IedConnectionException ("Failed to create data set", error); } + /// + /// Delete a data set. + /// + /// This function will delete a data set at the server. This function may fail if the data set is not + /// deletable. + /// The object reference of the data set + /// This exception is thrown if there is a connection or service error public void DeleteDataSet (string dataSetReference) { int error; @@ -615,7 +947,45 @@ namespace IEC61850 { return (IedClientError)this.errorCode; } - } + } + + public class FileDirectoryEntry + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr FileDirectoryEntry_getFileName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 FileDirectoryEntry_getFileSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt64 FileDirectoryEntry_getLastModified(IntPtr self); + + private string fileName; + private UInt32 fileSize; + private UInt64 lastModified; + + internal FileDirectoryEntry(IntPtr nativeFileDirectoryEntry) + { + fileName = Marshal.PtrToStringAnsi(FileDirectoryEntry_getFileName(nativeFileDirectoryEntry)); + fileSize = FileDirectoryEntry_getFileSize(nativeFileDirectoryEntry); + lastModified = FileDirectoryEntry_getLastModified(nativeFileDirectoryEntry); + } + + public string GetFileName() + { + return fileName; + } + + public UInt32 GetFileSize() + { + return fileSize; + } + + public UInt64 GetLastModified() + { + return lastModified; + } + } public enum IedClientError { @@ -680,10 +1050,15 @@ namespace IEC61850 [Flags] public enum TriggerOptions { NONE = 0, + /** send report when value of data changed */ DATA_CHANGED = 1, + /** send report when quality of data changed */ QUALITY_CHANGED = 2, + /** send report when data or quality is updated */ DATA_UPDATE = 4, + /** periodic transmission of all data set values */ INTEGRITY = 8, + /** general interrogation (on client request) */ GI = 16 } @@ -708,6 +1083,9 @@ namespace IEC61850 QUESTIONABLE = 3 } + /// + /// The quality of a data object. + /// public class Quality { @@ -740,16 +1118,27 @@ namespace IEC61850 public enum ACSIClass { + /** data objects */ ACSI_CLASS_DATA_OBJECT, + /** data sets (container for multiple data objects) */ ACSI_CLASS_DATA_SET, + /** buffered report control blocks */ ACSI_CLASS_BRCB, + /** unbuffered report control blocks */ ACSI_CLASS_URCB, + /** log control blocks */ ACSI_CLASS_LCB, + /** logs (journals) */ ACSI_CLASS_LOG, + /** setting group control blocks */ ACSI_CLASS_SGCB, + /** GOOSE control blocks */ ACSI_CLASS_GoCB, + /** GSE control blocks */ ACSI_CLASS_GsCB, + /** multicast sampled values control blocks */ ACSI_CLASS_MSVCB, + /** unicast sampled values control blocks */ ACSI_CLASS_USVCB } @@ -785,5 +1174,89 @@ namespace IEC61850 NONE = -1 } + public enum ControlAddCause { + ADD_CAUSE_UNKNOWN = 0, + ADD_CAUSE_NOT_SUPPORTED = 1, + ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2, + ADD_CAUSE_SELECT_FAILED = 3, + ADD_CAUSE_INVALID_POSITION = 4, + ADD_CAUSE_POSITION_REACHED = 5, + ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6, + ADD_CAUSE_STEP_LIMIT = 7, + ADD_CAUSE_BLOCKED_BY_MODE = 8, + ADD_CAUSE_BLOCKED_BY_PROCESS = 9, + ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10, + ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11, + ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12, + ADD_CAUSE_BLOCKED_BY_HEALTH = 13, + ADD_CAUSE_1_OF_N_CONTROL = 14, + ADD_CAUSE_ABORTION_BY_CANCEL = 15, + ADD_CAUSE_TIME_LIMIT_OVER = 16, + ADD_CAUSE_ABORTION_BY_TRIP = 17, + ADD_CAUSE_OBJECT_NOT_SELECTED = 18, + ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19, + ADD_CAUSE_NO_ACCESS_AUTHORITY = 20, + ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21, + ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22, + ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23, + ADD_CAUSE_ABORTION_BY_COMMAND = 24, + ADD_CAUSE_NONE = 25, + ADD_CAUSE_INCONSISTENT_PARAMETERS = 26, + ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27 + } + + /// + /// Object reference. Helper function to handle object reference strings. + /// + public static class ObjectReference { + + /// + /// Get the name part of an object reference with appended FC + /// + /// + /// The element name. + /// + /// + /// Object reference with appended fc. + /// + public static string getElementName (string objectReferenceWithFc) + { + int fcPartStartIndex = objectReferenceWithFc.IndexOf('['); + + if (fcPartStartIndex == -1) + return objectReferenceWithFc; + + return objectReferenceWithFc.Substring(0, fcPartStartIndex); + } + + /// + /// Get the FC of an object reference with appended FC. + /// + /// + /// The FC + /// + /// + /// Object reference with FC. + /// + public static FunctionalConstraint getFC (string objectReferenceWithFc) + { + int fcPartStartIndex = objectReferenceWithFc.IndexOf('['); + + if (fcPartStartIndex == -1) + return FunctionalConstraint.NONE; + + string fcString = objectReferenceWithFc.Substring(fcPartStartIndex + 1 , 2); + + try + { + return (FunctionalConstraint) Enum.Parse(typeof(FunctionalConstraint), fcString); + } + catch(ArgumentException) + { + return FunctionalConstraint.NONE; + } + } + } + } } diff --git a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj index 5c0e30c3..535e22ab 100644 --- a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj +++ b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj @@ -40,6 +40,7 @@ + \ No newline at end of file diff --git a/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs b/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs index 22aa246a..342dbc30 100644 --- a/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs +++ b/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs @@ -30,12 +30,26 @@ namespace IEC61850 { public enum AcseAuthenticationMechanism { + /** don't use authentication */ ACSE_AUTH_NONE = 0, + /** use password authentication */ ACSE_AUTH_PASSWORD = 1 } + /// + /// Connection parameters associated with the ISO protocol layers (transport, session, presentation, ACSE) + /// public class IsoConnectionParameters { + + [StructLayout(LayoutKind.Sequential)] + private struct NativeTSelector + { + public byte size; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] public byte[] value; + } + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern void IsoConnectionParameters_destroy(IntPtr self); @@ -43,13 +57,13 @@ namespace IEC61850 private static extern void IsoConnectionParameters_setRemoteApTitle(IntPtr self, string apTitle, int aeQualifier); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - private static extern void IsoConnectionParameters_setRemoteAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, UInt16 tSelector); + private static extern void IsoConnectionParameters_setRemoteAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, NativeTSelector tSelector); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern void IsoConnectionParameters_setLocalApTitle(IntPtr self, string apTitle, int aeQualifier); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - private static extern void IsoConnectionParameters_setLocalAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, UInt16 tSelector); + private static extern void IsoConnectionParameters_setLocalAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, NativeTSelector tSelector); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern void IsoConnectionParameters_setAcseAuthenticationParameter(IntPtr self, IntPtr acseAuthParameter); @@ -80,29 +94,97 @@ namespace IEC61850 if (authParameter != IntPtr.Zero) AcseAuthenticationParameter_destroy(authParameter); - IsoConnectionParameters_destroy(self); + //IsoConnectionParameters_destroy(self); } + /// + /// Sets the remote ap title related parameters + /// + /// + /// remote AP title. + /// + /// + /// remote AE qualifier. + /// public void SetRemoteApTitle(string apTitle, int aeQualifier) { IsoConnectionParameters_setRemoteApTitle(self, apTitle, aeQualifier); } - public void SetRemoteAddresses (UInt32 pSelector, UInt16 sSelector, UInt16 tSelector) + /// + /// Sets the remote addresses for ISO layers (transport, session, presentation) + /// + /// + /// presentation layer address + /// + /// + /// session layer address + /// + /// + /// ISO COTP transport layer address + /// + public void SetRemoteAddresses (UInt32 pSelector, UInt16 sSelector, byte[] tSelector) { - IsoConnectionParameters_setRemoteAddresses(self, pSelector, sSelector, tSelector); + if (tSelector.Length > 4) + throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded"); + + NativeTSelector nativeTSelector; + nativeTSelector.size = (byte) tSelector.Length; + nativeTSelector.value = new byte[4]; + + for (int i = 0; i < tSelector.Length; i++) + nativeTSelector.value[i] = tSelector[i]; + + IsoConnectionParameters_setRemoteAddresses(self, pSelector, sSelector, nativeTSelector); } + /// + /// Sets the local ap title related parameters + /// + /// + /// local AP title. + /// + /// + /// local AE qualifier. + /// public void SetLocalApTitle (string apTitle, int aeQualifier) { IsoConnectionParameters_setLocalApTitle(self, apTitle, aeQualifier); } - public void SetLocalAddresses (UInt32 pSelector, UInt16 sSelector, UInt16 tSelector) + /// + /// Sets the local addresses for ISO layers (transport, session, presentation) + /// + /// + /// presentation layer address + /// + /// + /// session layer address + /// + /// + /// ISO COTP transport layer address + /// + public void SetLocalAddresses (UInt32 pSelector, UInt16 sSelector, byte[] tSelector) { - IsoConnectionParameters_setLocalAddresses(self, pSelector, sSelector, tSelector); + if (tSelector.Length > 4) + throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded"); + + NativeTSelector nativeTSelector; + nativeTSelector.size = (byte) tSelector.Length; + nativeTSelector.value = new byte[4]; + + for (int i = 0; i < tSelector.Length; i++) + nativeTSelector.value[i] = tSelector[i]; + + IsoConnectionParameters_setLocalAddresses(self, pSelector, sSelector, nativeTSelector); } + /// + /// Instruct ACSE layer to use password authentication. + /// + /// + /// Password that will be used to authenticate the client + /// public void UsePasswordAuthentication (string password) { if (authParameter == IntPtr.Zero) { diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs index 7d54894a..0ab8c06b 100644 --- a/dotnet/IEC61850forCSharp/MmsValue.cs +++ b/dotnet/IEC61850forCSharp/MmsValue.cs @@ -25,12 +25,16 @@ using System; using System.Runtime.InteropServices; using System.Collections.Generic; -using System.Collections; +using System.Collections; +using System.Text; namespace IEC61850 { - namespace Client + namespace Common { + /// + /// This class is used to hold MMS data values of different types. + /// public class MmsValue : IEnumerable { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -48,6 +52,18 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 MmsValue_getBitStringAsInteger (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_setBitStringFromInteger(IntPtr self, UInt32 intValue); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsValue_getBitStringSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_setBitStringBit(IntPtr self, int bitPos, bool value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool MmsValue_getBitStringBit(IntPtr self, int bitPos); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern Int32 MmsValue_toInt32 (IntPtr self); @@ -87,9 +103,37 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr MmsValue_newIntegerFromInt32 (Int32 integer); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newUnsignedFromUint32(UInt32 integer); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr MmsValue_newIntegerFromInt64 (Int64 integer); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newBitString(int bitSize); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newVisibleString(string value); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_newOctetString(int size, int maxSize); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_setOctetString(IntPtr self, [Out] byte[] buf, int size); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 MmsValue_getOctetStringSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 MmsValue_getOctetStringMaxSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_getOctetStringBuffer(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool MmsValue_equals(IntPtr self, IntPtr otherValue); + + internal MmsValue (IntPtr value) { valueReference = value; @@ -122,33 +166,165 @@ namespace IEC61850 valueReference = MmsValue_newIntegerFromInt32 (value); } + public MmsValue (UInt32 value) + { + valueReference = MmsValue_newUnsignedFromUint32(value); + } + public MmsValue (long value) { valueReference = MmsValue_newIntegerFromInt64 (value); } + public MmsValue (string value) + { + valueReference = MmsValue_newVisibleString(value); + } + ~MmsValue () { if (responsableForDeletion) MmsValue_delete (valueReference); } + /// + /// Create a new MmsValue instance of type MMS_BIT_STRING. + /// + /// + /// the new MmsValue instance + /// + /// + /// the size of the bit string in bits. + /// + public static MmsValue NewBitString(int bitSize) + { + IntPtr newValue = MmsValue_newBitString(bitSize); + + return new MmsValue(newValue, true); + } + + /// + /// Create a new MmsValue instance of type MMS_OCTET_STRING. + /// + /// + /// the new MmsValue instance + /// + /// + /// the maximum size of the octet string in bytes + /// + /// + /// the current size of the octet string in bytes (defaults to 0) + /// + public static MmsValue NewOctetString (int maxSize, int size = 0) + { + IntPtr newValue = MmsValue_newOctetString(size, maxSize); + + return new MmsValue(newValue, true); + } + internal IntPtr valueReference; private bool responsableForDeletion; + /// + /// Gets the type of the value + /// + /// + /// The type. + /// public new MmsType GetType () { return (MmsType)MmsValue_getType (valueReference); } + /// + /// Gets the size of an array, structure, or bit string + /// + /// + /// + /// Return the size of an array of structure (number of elements) + /// The value has to be of type MMS_ARRAY, MMS_STRUCTURE, MMS_BIT_STRING ... + /// + /// the number of elements (array/structure elements, octets, bits depending on type) + /// + /// This exception is thrown if the value has the wrong type. public int Size () { if ((GetType () == MmsType.MMS_ARRAY) || (GetType () == MmsType.MMS_STRUCTURE)) { return MmsValue_getArraySize (valueReference); - } else - throw new MmsValueException ("Value is not a complex type"); + } else if (GetType () == MmsType.MMS_BIT_STRING) { + return MmsValue_getBitStringSize(valueReference); + } + else if (GetType () == MmsType.MMS_OCTET_STRING) { + return MmsValue_getOctetStringSize(valueReference); + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + /// + /// Gets the maximum size of an octet string + /// + /// + /// The maximum size (in bytes) of the octet string + /// + public int MaxSize () + { + if (GetType () == MmsType.MMS_OCTET_STRING) { + return MmsValue_getOctetStringMaxSize(valueReference); + } + else + throw new MmsValueException ("Operation not supported for this type"); } + /// + /// Gets the octet string as byte array + /// + /// Instance has to be of type MMS_OCTET_STRING. + /// + /// + /// Byte array containing the bytes of the octet string. + /// + /// This exception is thrown if the value has the wrong type. + public byte[] getOctetString () + { + if (GetType () == MmsType.MMS_OCTET_STRING) { + IntPtr buffer = MmsValue_getOctetStringBuffer(valueReference); + int bufferSize = this.Size(); + + byte[] octetString = new byte[bufferSize]; + + Marshal.Copy(buffer, octetString, 0, bufferSize); + + return octetString; + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + public void setOctetString (byte[] octetString) + { + if (GetType () == MmsType.MMS_OCTET_STRING) { + + if (this.MaxSize() < octetString.Length) + throw new MmsValueException("octet string is to large"); + + MmsValue_setOctetString(valueReference, octetString, octetString.Length); + } + else + throw new MmsValueException ("Operation not supported for this type"); + } + + /// + /// Get an element of an array or structure + /// + /// + /// the MmsValue element. + /// + /// + /// index of the element starting with 0 + /// + /// This exception is thrown if the value has the wrong type. + /// This exception is thrown if the index is out of range. public MmsValue GetElement (int index) { MmsType type = GetType (); @@ -163,6 +339,17 @@ namespace IEC61850 throw new MmsValueException ("Value is of wrong type"); } + /// + /// Gets the timestamp value as UTC time in s (UNIX time stamp). + /// + /// + /// Return the value as seconds since epoch (1.1.1970 UTC). + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// The UTC time in seconds (UNIX time stamp). + /// + /// This exception is thrown if the value has the wrong type. public UInt32 ToUnixTimestamp () { if (GetType () == MmsType.MMS_UTC_TIME) @@ -171,6 +358,17 @@ namespace IEC61850 throw new MmsValueException ("Value is not a time type"); } + /// + /// Gets the timestamp value as UTC time in ms. + /// + /// + /// Return the value as milliseconds since epoch (1.1.1970 UTC). + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// The UTC time in ms. + /// + /// This exception is thrown if the value has the wrong type. public ulong GetUtcTimeInMs () { if (GetType () == MmsType.MMS_UTC_TIME) { @@ -179,13 +377,33 @@ namespace IEC61850 throw new MmsValueException ("Value is not a time type"); } + /// + /// Convert a millisecond time (milliseconds since epoch) to DataTimeOffset + /// + /// + /// The time as DataTimeOffset + /// + /// + /// the millisecond time + /// public static DateTimeOffset MsTimeToDateTimeOffset (UInt64 msTime) { DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero); - return retVal.AddMilliseconds (msTime); + return retVal.AddMilliseconds ((double) msTime); } + /// + /// Convert MMS_UTC_TIME to DateTimeOffset instance + /// + /// + /// Return the value as DateTimeOffset instance. + /// The value has to be of type MMS_UTC_TIME. + /// + /// + /// the value as DataTimeOffset instance + /// + /// This exception is thrown if the value has the wrong type. public DateTimeOffset GetUtcTimeAsDateTimeOffset () { if (GetType () == MmsType.MMS_UTC_TIME) @@ -194,36 +412,123 @@ namespace IEC61850 throw new MmsValueException ("Value is not a time type"); } + + /// + /// Return the value as 32 bit signed integer. + /// + /// + /// Return the value as 32 bit signed integer (Int32). + /// The value has to be of type MMS_INTEGER. + /// + /// + /// the value if the object as 32 bit signed integer + /// + /// This exception is thrown if the value has the wrong type. public Int32 ToInt32 () { if (GetType () != MmsType.MMS_INTEGER) throw new MmsValueException ("Value type is not integer"); - Int32 retVal = MmsValue_toInt32 (valueReference); - - return retVal; + return MmsValue_toInt32 (valueReference); } + /// + /// Return the value as 64 bit signed integer. + /// + /// + /// Return the value as 64 bit signed integer (Int64). + /// The value has to be of type MMS_INTEGER. + /// + /// + /// the value if the object as 64 bit signed integer + /// + /// This exception is thrown if the value has the wrong type. public Int64 ToInt64 () { if (GetType () != MmsType.MMS_INTEGER) throw new MmsValueException ("Value type is not integer"); - Int64 retVal = MmsValue_toInt64 (valueReference); - - return retVal; + return MmsValue_toInt64 (valueReference); } + /// + /// Return the value as 32 bit unsigned integer. + /// + /// + /// Return the value as 32 bit unsigned integer (Int32). + /// The value has to be of type MMS_INTEGER. + /// + /// + /// the value if the object as 32 bit unsigned integer + /// + /// This exception is thrown if the value has the wrong type. public UInt32 ToUint32 () { if (GetType () != MmsType.MMS_UNSIGNED) throw new MmsValueException ("Value type is not unsigned"); - UInt32 retVal = MmsValue_toUint32 (valueReference); + return MmsValue_toUint32 (valueReference); + } + + public UInt32 BitStringToUInt32 () + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + return MmsValue_getBitStringAsInteger(valueReference); + } - return retVal; + public void BitStringFromUInt32 (UInt32 intValue) + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + MmsValue_setBitStringFromInteger(valueReference, intValue); } + public void SetBit (int bitPos, bool bitValue) + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + MmsValue_setBitStringBit(valueReference, bitPos, bitValue); + } + + public bool GetBit (int bitPos) + { + if (GetType () != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + return MmsValue_getBitStringBit(valueReference, bitPos); + } + + private string GetBitStringAsString() + { + if (GetType() != MmsType.MMS_BIT_STRING) + throw new MmsValueException("Value type is not bit string"); + + int size = Size(); + + StringBuilder builder = new StringBuilder(size); + + for (int i = 0; i < size; i++) + { + if (MmsValue_getBitStringBit(valueReference, i)) + builder.Append('1'); + else + builder.Append('0'); + } + + return builder.ToString(); + } + + /// + /// Gets the boolean value + /// + /// + /// The boolean value + /// + /// This exception is thrown if the value has the wrong type. public bool GetBoolean () { if (GetType () == MmsType.MMS_BOOLEAN) @@ -232,6 +537,13 @@ namespace IEC61850 throw new MmsValueException ("Value type is not boolean"); } + /// + /// Gets the float value of an MMS_FLOAT instance + /// + /// + /// The float value + /// + /// This exception is thrown if the value has the wrong type. public float ToFloat () { if (GetType () == MmsType.MMS_FLOAT) @@ -240,6 +552,13 @@ namespace IEC61850 throw new MmsValueException ("Value type is not float"); } + /// + /// Gets the double value of an MMS_FLOAT instance + /// + /// + /// The float value + /// + /// This exception is thrown if the value has the wrong type. public double ToDouble () { if (GetType () == MmsType.MMS_FLOAT) @@ -248,6 +567,13 @@ namespace IEC61850 throw new MmsValueException ("Value type is not float"); } + public override bool Equals (object obj) + { + MmsValue otherValue = (MmsValue) obj; + + return MmsValue_equals(this.valueReference, otherValue.valueReference); + } + // override standard ToString() method public override string ToString () { @@ -265,6 +591,8 @@ namespace IEC61850 return ToDouble ().ToString (); case MmsType.MMS_UTC_TIME: return GetUtcTimeAsDateTimeOffset ().ToString (); + case MmsType.MMS_BIT_STRING: + return GetBitStringAsString(); default: return "unknown"; } @@ -321,21 +649,37 @@ namespace IEC61850 public enum MmsType { + /** array type (multiple elements of the same type) */ MMS_ARRAY = 0, + /** structure type (multiple elements of different types) */ MMS_STRUCTURE = 1, + /** boolean */ MMS_BOOLEAN = 2, + /** bit string */ MMS_BIT_STRING = 3, + /** signed integer */ MMS_INTEGER = 4, + /** unsigned integer */ MMS_UNSIGNED = 5, + /** floating point value (32 or 64 bit) */ MMS_FLOAT = 6, + /** octet string */ MMS_OCTET_STRING = 7, + /** visible string - ANSI string */ MMS_VISIBLE_STRING = 8, + /** Generalized time */ MMS_GENERALIZED_TIME = 9, + /** Binary time */ MMS_BINARY_TIME = 10, + /** Binary coded decimal (BCD) - not used */ MMS_BCD = 11, + /** object ID - not used */ MMS_OBJ_ID = 12, + /** Unicode string */ MMS_STRING = 13, + /** UTC time */ MMS_UTC_TIME = 14, + /** will be returned in case of an error (contains error code) */ MMS_DATA_ACCESS_ERROR = 15 } diff --git a/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs b/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs new file mode 100644 index 00000000..159f10e6 --- /dev/null +++ b/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs @@ -0,0 +1,201 @@ +/* + * MmsVariableSpecification.cs + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ +using System; + +using System.Runtime.InteropServices; +using System.Collections.Generic; + +using System.Collections; + +namespace IEC61850 +{ + namespace Common + { + /// + /// MMS variable specification. This class is used to represent an MMS variable type definition. + /// + public class MmsVariableSpecification : IEnumerable + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsVariableSpecification_destroy(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getChildValue(IntPtr self, IntPtr value, string childId); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getNamedVariableRecursive(IntPtr variable, string nameId); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsVariableSpecification_getType(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsVariableSpecification_getSize(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getChildSpecificationByIndex(IntPtr self, int index); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsVariableSpecification_getArrayElementSpecification(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsVariableSpecification_getExponentWidth(IntPtr self); + + private IntPtr self; + private bool responsableForDeletion; + + internal MmsVariableSpecification (IntPtr self) + { + this.self = self; + this.responsableForDeletion = false; + } + + internal MmsVariableSpecification (IntPtr self, bool responsableForDeletion) + { + this.self = self; + this.responsableForDeletion = responsableForDeletion; + } + + ~MmsVariableSpecification () + { + if (responsableForDeletion) + MmsVariableSpecification_destroy(self); + } + + /// + /// Gets the MmsValue type of the variable + /// + /// + /// The MmsType of the variable + /// + public new MmsType GetType () + { + return (MmsType) MmsVariableSpecification_getType(self); + } + + /// + /// Gets the type of the array elements. + /// + /// + /// The array element type. + /// + /// This exception is thrown if the value is not of type MMS_ARRAY + public MmsVariableSpecification getArrayElementType () + { + if (GetType() == MmsType.MMS_ARRAY) { + IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self); + return new MmsVariableSpecification(varSpecPtr); + } + else + throw new MmsValueException ("specification is of wrong type"); + } + + /// + /// Gets the element specification of a structure element + /// + /// + /// The element of the structure at given index + /// + /// + /// Index. + /// + public MmsVariableSpecification GetElement (int index) + { + if (GetType () == MmsType.MMS_STRUCTURE) { + + if ((index >= 0) && (index < Size ())) { + IntPtr varSpecPtr = MmsVariableSpecification_getChildSpecificationByIndex(self, index); + return new MmsVariableSpecification(varSpecPtr); + } + else + throw new MmsValueException ("Index out of bounds"); + } + else + throw new MmsValueException ("specification is of wrong type"); + } + + /// + /// Gets the name of the variable + /// + /// + /// The name. + /// + public string GetName () + { + IntPtr namePtr = MmsVariableSpecification_getName(self); + + return Marshal.PtrToStringAnsi (namePtr); + } + + /// + /// Get the "size" of the variable (array size, number of structure elements ...) + /// + public int Size () + { + return MmsVariableSpecification_getSize(self); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return new MmsVariableSpecificationEnumerator (this); + } + + private class MmsVariableSpecificationEnumerator : IEnumerator + { + private MmsVariableSpecification value; + private int index = -1; + + public MmsVariableSpecificationEnumerator (MmsVariableSpecification value) + { + this.value = value; + } + + #region IEnumerator Members + public void Reset () + { + index = -1; + } + + public object Current { + + get { return value.GetElement (index);} + } + + public bool MoveNext () + { + index++; + + if (index >= value.Size ()) + return false; + else + return true; + } + + #endregion + } + + } + } +} diff --git a/dotnet/IEC61850forCSharp/ReportControlBlock.cs b/dotnet/IEC61850forCSharp/ReportControlBlock.cs index e86ffae1..de66949d 100644 --- a/dotnet/IEC61850forCSharp/ReportControlBlock.cs +++ b/dotnet/IEC61850forCSharp/ReportControlBlock.cs @@ -31,8 +31,19 @@ namespace IEC61850 namespace Client { + /// + /// Report handler. + /// public delegate void ReportHandler (Report report, object parameter); + /// + /// Report control block (RCB) representation. + /// + /// + /// This class is used as a client side representation (copy) of a report control block (RCB). + /// Values from the server will only be read when the GetRCBValues method is called. + /// Values at the server are only affected when the SetRCBValues method is called. + /// public class ReportControlBlock { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -133,12 +144,11 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_installReportHandler (IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler, - IntPtr handlerParameter); - + IntPtr handlerParameter); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void InternalReportHandler (IntPtr parameter, IntPtr report); - - private IntPtr self; private IntPtr connection; private string objectReference; @@ -183,8 +193,6 @@ namespace IEC61850 private void internalReportHandler (IntPtr parameter, IntPtr report) { - Console.WriteLine ("internalReportHandler called " + this); - try { if (this.report == null) @@ -207,20 +215,42 @@ namespace IEC61850 this.objectReference = objectReference; } + /// + /// Installs the report handler. + /// + /// + /// This will install a callback handler (delegate) that is invoked whenever a report + /// related this RCB is received. Any call of this method will replace an previously registered + /// handler! + /// + /// + /// report handler + /// + /// + /// parameter is passed to the handler when the handler is invoked. + /// public void InstallReportHandler (ReportHandler reportHandler, object parameter) { this.reportHandler = new ReportHandler(reportHandler); - Console.WriteLine("Installed report handler " + this.reportHandler); - this.reportHandlerParameter = parameter; if (reportHandlerInstalled == false) { - IedConnection_installReportHandler (this.connection, objectReference, this.GetRptId (), new InternalReportHandler(internalReportHandler), IntPtr.Zero); + + string reportId = this.GetRptId (); + +// if ((GetRptId() == null) || (GetRptId().Length == 0)) +// reportId = + + IedConnection_installReportHandler (this.connection, objectReference, reportId, new InternalReportHandler(internalReportHandler), IntPtr.Zero); reportHandlerInstalled = true; } } + /// + /// Read all RCB values from the server + /// + /// This exception is thrown if there is a connection or service error public void GetRCBValues () { int error; @@ -231,84 +261,142 @@ namespace IEC61850 throw new IedConnectionException ("getRCBValues service failed", error); } + /// + /// Write changed RCB values to the server. + /// + /// + /// This function will only write the RCB values that were set by one of the setter methods. + /// The RCB values are sent by a single MMS write request. + /// + /// This exception is thrown if there is a connection or service error public void SetRCBValues () { SetRCBValues (true); } + /// + /// Write changed RCB values to the server. + /// + /// + /// This function will only write the RCB values that were set by one of the setter methods. + /// + /// This exception is thrown if there is a connection or service error + /// + /// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests. + /// public void SetRCBValues (bool singleRequest) - { - UInt32 parametersMask = 0; + { + UInt32 parametersMask = 0; - if (flagRptId) - parametersMask += 1; + if (flagRptId) + parametersMask += 1; - if (flagRptEna) - parametersMask += 2; + if (flagRptEna) + parametersMask += 2; - if (flagResv) - parametersMask += 4; + if (flagResv) + parametersMask += 4; - if (flagDataSetReference) - parametersMask += 8; + if (flagDataSetReference) + parametersMask += 8; - if (flagConfRev) - parametersMask += 16; + if (flagConfRev) + parametersMask += 16; - if (flagOptFlds) - parametersMask += 32; + if (flagOptFlds) + parametersMask += 32; - if (flagBufTm) - parametersMask += 64; + if (flagBufTm) + parametersMask += 64; - if (flagSqNum) - parametersMask += 128; + if (flagSqNum) + parametersMask += 128; - if (flagTrgOps) - parametersMask += 256; + if (flagTrgOps) + parametersMask += 256; - if (flagIntgPd) - parametersMask += 512; + if (flagIntgPd) + parametersMask += 512; - if (flagGI) - parametersMask += 1024; + if (flagGI) + parametersMask += 1024; - if (flagPurgeBuf) - parametersMask += 2048; + if (flagPurgeBuf) + parametersMask += 2048; - if (flagEntryId) - parametersMask += 4096; + if (flagEntryId) + parametersMask += 4096; - if (flagResvTms) - parametersMask += 16384; + if (flagResvTms) + parametersMask += 16384; - int error; + int error; - IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest); + IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest); - if (error != 0) - throw new IedConnectionException ("setRCBValues service failed", error); + if (error != 0) + throw new IedConnectionException ("setRCBValues service failed", error); + + if (flagRptId) { + + if (reportHandlerInstalled) { + reportHandlerInstalled = false; + InstallReportHandler(this.reportHandler, this.reportHandlerParameter); + } + } + + resetSendFlags(); } + /// + /// Determines whether this instance is a buffered or unbuffered RCB. + /// + /// + /// true if this instance is a buffered RCB; otherwise, false. + /// public bool IsBuffered () { return ClientReportControlBlock_isBuffered (self); } - public UInt64 getEntryTime () + /// + /// Gets the entry time of the RCB as ms time + /// + /// + /// The entry time is the timestamp of the last report sent. + /// + /// + /// The entry time as ms timestamp + /// + public UInt64 GetEntryTime () { return ClientReportControlBlock_getEntryTime (self); } + /// + /// Gets the entry time of the RCB as DateTimeOffset + /// + /// + /// The entry time is the timestamp of the last report sent. + /// + /// + /// The entry time as DataTimeOffset + /// public DateTimeOffset GetEntryTimeAsDateTimeOffset () { - UInt64 entryTime = getEntryTime (); + UInt64 entryTime = GetEntryTime (); DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero); return retVal.AddMilliseconds (entryTime); } + /// + /// Gets the data set reference of the associated data set + /// + /// + /// The data set reference. + /// public string GetDataSetReference () { IntPtr dataSetRefPtr = ClientReportControlBlock_getDataSetReference (self); @@ -316,6 +404,12 @@ namespace IEC61850 return Marshal.PtrToStringAnsi (dataSetRefPtr); } + /// + /// Sets the data set reference. Use this method to select the associated data set for the RCB + /// + /// + /// The data set reference. + /// public void SetDataSetReference (string dataSetReference) { ClientReportControlBlock_setDataSetReference (self, dataSetReference); @@ -323,6 +417,12 @@ namespace IEC61850 flagDataSetReference = true; } + /// + /// Gets the report identifier. + /// + /// + /// The report identifier. + /// public string GetRptId () { IntPtr rptIdPtr = ClientReportControlBlock_getRptId (self); @@ -330,22 +430,58 @@ namespace IEC61850 return Marshal.PtrToStringAnsi (rptIdPtr); } + /// + /// Sets the RptId (report ID) of the RCB + /// + /// + /// The new RptId + /// + public void SetRptId (string rptId) + { + ClientReportControlBlock_setRptId(self, rptId); + flagRptId = true; + } + + /// + /// Check if reporting is currently enabled + /// + /// + /// true, if reporting is enabled, false otherwise + /// public bool GetRptEna () { return ClientReportControlBlock_getRptEna (self); } + /// + /// Sets report enable flag. Use this to enable reporting + /// + /// + /// true to enable reporting, false to disable + /// public void SetRptEna (bool rptEna) { ClientReportControlBlock_setRptEna (self, rptEna); flagRptEna = true; } + /// + /// Gets the buffer time. + /// + /// + /// The buffer time in ms. + /// public UInt32 GetBufTm() { return ClientReportControlBlock_getBufTm (self); } + /// + /// Sets the buffer time. + /// + /// + /// Buffer time is ms. + /// public void SetBufTm (UInt32 bufTm) { ClientReportControlBlock_setBufTm (self, bufTm); @@ -353,33 +489,80 @@ namespace IEC61850 flagBufTm = true; } + /// + /// Gets the GI flag + /// + /// + /// true, if GI flag is set + /// public bool GetGI () { return ClientReportControlBlock_getGI (self); } + /// + /// Sets the GI flag. Use this to trigger a GI (general interrogation) command. + /// + /// + /// request general interrogation of true + /// public void SetGI (bool GI) { ClientReportControlBlock_setGI (self, GI); flagGI = true; } + /// + /// Check if RCB is reserved by a client + /// + /// + /// true, the RCB is reserver by a client + /// public bool GetResv () { return ClientReportControlBlock_getResv (self); } + /// + /// Gets the configuration revision of the RCB + /// + /// + /// The conf rev. + /// + public UInt32 GetConfRev () + { + return ClientReportControlBlock_getConfRev (self); + } + + /// + /// Sets RESV flag. Use this to reserve (allocate) this RCB. + /// + /// + /// true: reserver this RCB for exclusive use + /// public void SetResv (bool resv) { ClientReportControlBlock_setResv (self, resv); flagResv = true; } + /// + /// Gets the trigger options of the RCB + /// + /// + /// trigger options + /// public TriggerOptions GetTrgOps() { return (TriggerOptions) ClientReportControlBlock_getTrgOps (self); } + /// + /// Sets the trigger options of the RCB. + /// + /// + /// trigger options + /// public void SetTrgOps(TriggerOptions trgOps) { ClientReportControlBlock_setTrgOps (self, (int) trgOps); @@ -387,22 +570,46 @@ namespace IEC61850 flagTrgOps = true; } + /// + /// Gets the integrity period + /// + /// + /// integrity period in ms + /// public UInt32 GetIntgPd () { return ClientReportControlBlock_getIntgPd (self); } + /// + /// Sets the integrity period + /// + /// + /// integrity period in ms + /// public void SetIntgPd (UInt32 intgPd) { ClientReportControlBlock_setIntgPd (self, intgPd); flagIntgPd = true; } + /// + /// Gets the option fields. + /// + /// + /// The option fields + /// public ReportOptions GetOptFlds() { return (ReportOptions) ClientReportControlBlock_getOptFlds (self); } + /// + /// Sets the option field. Used to enable or disable optional report elements + /// + /// + /// Option field. + /// public void SetOptFlds(ReportOptions optFlds) { ClientReportControlBlock_setOptFlds (self, (int)optFlds); diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs index 3cdd9d1e..4bade8e5 100644 --- a/dotnet/IEC61850forCSharp/Reporting.cs +++ b/dotnet/IEC61850forCSharp/Reporting.cs @@ -23,13 +23,15 @@ using System; using System.Runtime.InteropServices; +using IEC61850.Common; + namespace IEC61850 { namespace Client { public partial class IedConnection { - public ReportControlBlock getReportControlBlock (string rcbObjectReference) + public ReportControlBlock GetReportControlBlock (string rcbObjectReference) { return new ReportControlBlock (rcbObjectReference, connection); } @@ -59,6 +61,9 @@ namespace IEC61850 REASON_UNKNOWN = 6 } + /// + /// A class to hold the contents of a received report + /// public class Report { @@ -74,6 +79,37 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern int ClientReport_getReasonForInclusion(IntPtr self, int elementIndex); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool ClientReport_hasSeqNum(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 ClientReport_getSeqNum(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool ClientReport_hasDataSetName(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool ClientReport_hasReasonForInclusion(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool ClientReport_hasConfRev(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ClientReport_getConfRev(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool ClientReport_hasBufOvfl(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern bool ClientReport_hasDataReference(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getRcbReference(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ClientReport_getRptId(IntPtr self); + + private IntPtr self; private IntPtr dataSetValues = IntPtr.Zero; @@ -85,11 +121,23 @@ namespace IEC61850 this.self = self; } + /// + /// Determines whether the report has a timestamp. + /// + /// + /// true if this report has a timestamp; otherwise, false. + /// public bool HasTimestamp () { return ClientReport_hasTimestamp (self); } + /// + /// Gets the timestamp. + /// + /// + /// The timestamp as milliseconds since 1.1.1970 UTC 00:00 or 0 if no timestamp is present. + /// public UInt64 GetTimestamp () { if (HasTimestamp ()) @@ -98,6 +146,52 @@ namespace IEC61850 return 0; } + public bool HasDataSetName () + { + return ClientReport_hasDataSetName(self); + } + + public bool HasDataReference () + { + return ClientReport_hasDataReference(self); + } + + public bool HasConfRev () + { + return ClientReport_hasConfRev(self); + } + + public UInt32 GetConfRev () + { + return ClientReport_getConfRev(self); + } + + public bool HasBufOvfl () + { + return ClientReport_hasBufOvfl(self); + } + + public bool HasSeqNum () + { + return ClientReport_hasSeqNum(self); + } + + public UInt16 GetSeqNum () + { + return ClientReport_getSeqNum(self); + } + + public bool HasReasonForInclusion () + { + return ClientReport_hasReasonForInclusion(self); + } + + /// + /// Gets the data set values as MMS_ARRAY instance. + /// + /// + /// The data set values. + /// public MmsValue GetDataSetValues () { if (dataSetValues == IntPtr.Zero) { @@ -112,6 +206,15 @@ namespace IEC61850 return values; } + /// + /// Gets the reason for inclusion of data set member with the given index + /// + /// + /// The reason for inclusion. + /// + /// + /// index of the data set member in the data set + /// public ReasonForInclusion GetReasonForInclusion (int index) { if (values == null) { @@ -129,6 +232,23 @@ namespace IEC61850 return (ReasonForInclusion) ClientReport_getReasonForInclusion(self, index); } + public string GetRcbReference () + { + IntPtr rcbRef = ClientReport_getRcbReference(self); + + return Marshal.PtrToStringAnsi (rcbRef); + } + + public string GetRptId () + { + IntPtr rptId = ClientReport_getRptId(self); + + if (rptId == IntPtr.Zero) + return GetRcbReference(); + else + return Marshal.PtrToStringAnsi (rptId); + } + } } diff --git a/dotnet/control/ControlExample.cs b/dotnet/control/ControlExample.cs index 8da9f4cd..1ca2b515 100644 --- a/dotnet/control/ControlExample.cs +++ b/dotnet/control/ControlExample.cs @@ -2,12 +2,19 @@ using System; using System.Collections.Generic; using IEC61850.Common; using IEC61850.Client; +using System.Threading; namespace control { class ControlExample { + private static void commandTerminationHandler (Object parameter, ControlObject control) + { + LastApplError lastApplError = control.GetLastApplError(); + Console.WriteLine("HANDLER CALLED! " + lastApplError.addCause); + } + public static void Main (string[] args) { IedConnection con = new IedConnection (); @@ -25,7 +32,8 @@ namespace control { con.Connect(hostname, 102); - string objectReference = "IEDM1CPUBHKW/DRCC1.DERStr"; + /* direct control with normal security */ + string objectReference = "simpleIOGenericIO/GGIO1.SPCSO1"; ControlObject control = con.CreateControlObject(objectReference); @@ -33,9 +41,27 @@ namespace control Console.WriteLine(objectReference + " has control model " + controlModel.ToString()); + if (controlModel != ControlModel.CONTROL_MODEL_STATUS_ONLY) + control.Operate(true); + if (!control.Operate(true)) Console.WriteLine("operate failed!"); + /* direct control with enhanced security */ + objectReference = "simpleIOGenericIO/GGIO1.SPCSO3"; + control = con.CreateControlObject(objectReference); + + controlModel = control.GetControlModel(); + Console.WriteLine(objectReference + " has control model " + controlModel.ToString()); + + if (controlModel == ControlModel.CONTROL_MODEL_DIRECT_ENHANCED) { + control.SetCommandTerminationHandler(commandTerminationHandler, null); + + control.Operate(true); + + Thread.Sleep(1000); + } + con.Abort(); diff --git a/dotnet/datasets/DataSetExample.cs b/dotnet/datasets/DataSetExample.cs index f6a11493..bd73cd54 100644 --- a/dotnet/datasets/DataSetExample.cs +++ b/dotnet/datasets/DataSetExample.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using IEC61850.Client; +using IEC61850.Common; namespace datasets { @@ -16,7 +17,7 @@ namespace datasets if (args.Length > 0) hostname = args[0]; else - hostname = "10.0.2.2"; + hostname = "localhost"; Console.WriteLine("Connect to " + hostname); @@ -31,7 +32,6 @@ namespace datasets Console.WriteLine("LD: " + entry); } - // create a new data set List dataSetElements = new List(); @@ -49,7 +49,6 @@ namespace datasets Console.WriteLine("DS element: " + entry); } - // read the values of the newly created data set DataSet dataSet = con.ReadDataSetValues("IEDM1CPUBHKW/LLN0.ds1", null); diff --git a/dotnet/dotnet.sln b/dotnet/dotnet.sln index 8265db95..e781ee8a 100644 --- a/dotnet/dotnet.sln +++ b/dotnet/dotnet.sln @@ -19,6 +19,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "authenticate", "authenticat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{FBDFE530-DBEB-474B-BA54-9AB287DD57B3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -37,6 +41,14 @@ Global {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Release|Any CPU.ActiveCfg = Release|Any CPU {59B85486-F48D-4978-BD35-8F5C3A8288D4}.Release|Any CPU.Build.0 = Release|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Release|Any CPU.Build.0 = Release|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Release|Any CPU.Build.0 = Release|Any CPU {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/dotnet/example3/AssemblyInfo.cs b/dotnet/example3/AssemblyInfo.cs new file mode 100644 index 00000000..8fa9151c --- /dev/null +++ b/dotnet/example3/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("example3")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/example3/Main.cs b/dotnet/example3/Main.cs new file mode 100644 index 00000000..5f04ce98 --- /dev/null +++ b/dotnet/example3/Main.cs @@ -0,0 +1,48 @@ +using System; +using IEC61850.Client; +using System.Collections.Generic; + +namespace example3 +{ + class MainClass + { + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "localhost"; + + Console.WriteLine("Connect to " + hostname); + + + try + { + IsoConnectionParameters parameters = con.GetConnectionParameters(); + + parameters.SetRemoteAddresses(1,1, new byte[] {0x00, 0x01, 0x02, 0x03}); + + con.ConnectTimeout = 10000; + + con.Connect(hostname, 102); + + List serverDirectory = con.GetServerDirectory(false); + + foreach (string entry in serverDirectory) + { + Console.WriteLine("LD: " + entry); + } + + con.Release(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + } + } +} diff --git a/dotnet/example3/example3.csproj b/dotnet/example3/example3.csproj new file mode 100644 index 00000000..7a1f9d03 --- /dev/null +++ b/dotnet/example3/example3.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2} + Exe + example3 + example3 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/files/AssemblyInfo.cs b/dotnet/files/AssemblyInfo.cs new file mode 100644 index 00000000..1133bf62 --- /dev/null +++ b/dotnet/files/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("files")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("mzillgit")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/dotnet/files/FileServicesExample.cs b/dotnet/files/FileServicesExample.cs new file mode 100644 index 00000000..ccc94a0a --- /dev/null +++ b/dotnet/files/FileServicesExample.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; + +using IEC61850.Client; +using IEC61850.Common; +using System.IO; + +namespace files +{ + class MainClass + { + public static void printFiles (IedConnection con, string prefix, string parent) + { + List files = con.GetFileDirectory (parent); + + foreach (FileDirectoryEntry file in files) { + Console.WriteLine(prefix + file.GetFileName() + "\t" + file.GetFileSize() + "\t" + + MmsValue.MsTimeToDateTimeOffset(file.GetLastModified())); + + if (file.GetFileName().EndsWith("/")) { + printFiles (con, prefix + " ", parent + file.GetFileName()); + } + } + + } + + static bool getFileHandler (object parameter, byte[] data) + { + Console.WriteLine("received " + data.Length + " bytes"); + + BinaryWriter binWriter = (BinaryWriter) parameter; + + binWriter.Write(data); + + return true; + } + + + public static void Main (string[] args) + { + IedConnection con = new IedConnection (); + + string hostname; + + if (args.Length > 0) + hostname = args[0]; + else + hostname = "10.0.2.2"; + + Console.WriteLine("Connect to " + hostname); + + try + { + con.Connect(hostname, 102); + + Console.WriteLine ("Files in server root directory:"); + List serverDirectory = con.GetServerDirectory(true); + + foreach (string entry in serverDirectory) { + Console.WriteLine(entry); + } + + Console.WriteLine(); + + Console.WriteLine ("File directory tree at server:"); + printFiles(con, "", ""); + Console.WriteLine(); + + string filename = "IEDSERVER.BIN"; + + Console.WriteLine("Download file " + filename); + + /* Download file from server and write it to a new local file */ + FileStream fs = new FileStream(filename, FileMode.Create); + BinaryWriter w = new BinaryWriter(fs); + + con.GetFile(filename, new IedConnection.GetFileHandler(getFileHandler), w); + + fs.Close(); + + con.Abort(); + } + catch (IedConnectionException e) + { + Console.WriteLine(e.Message); + } + } + } +} diff --git a/dotnet/files/files.csproj b/dotnet/files/files.csproj new file mode 100644 index 00000000..348f8045 --- /dev/null +++ b/dotnet/files/files.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {77127456-19B9-4D1A-AEF9-40F8D1C5695E} + Exe + files + files + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + none + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + {C35D624E-5506-4560-8074-1728F1FA1A4D} + IEC61850forCSharp + + + \ No newline at end of file diff --git a/dotnet/model_browsing/ModelBrowsing.cs b/dotnet/model_browsing/ModelBrowsing.cs index 71bc1b39..ce4f7fec 100644 --- a/dotnet/model_browsing/ModelBrowsing.cs +++ b/dotnet/model_browsing/ModelBrowsing.cs @@ -51,6 +51,27 @@ namespace model_browsing foreach (string dataObject in dataObjects) { Console.WriteLine(" DO: " + dataObject); + + List dataDirectory = con.GetDataDirectoryFC(logicalNodeReference + "." + dataObject); + + foreach (string dataDirectoryElement in dataDirectory) { + + string daReference = logicalNodeReference + "." + dataObject + "." + ObjectReference.getElementName(dataDirectoryElement); + + // get the type specification of a variable + MmsVariableSpecification specification = con.GetVariableSpecification(daReference, ObjectReference.getFC(dataDirectoryElement)); + + Console.WriteLine (" DA/SDO: [" + ObjectReference.getFC(dataDirectoryElement) + "] " + + ObjectReference.getElementName(dataDirectoryElement) + " : " + specification.GetType() + + "(" + specification.Size() + ")"); + + if (specification.GetType() == MmsType.MMS_STRUCTURE) { + foreach (MmsVariableSpecification elementSpec in specification) { + Console.WriteLine(" " + elementSpec.GetName() + " : " + elementSpec.GetType()); + } + } + } + } // discover data sets diff --git a/dotnet/reporting/ReportingExample.cs b/dotnet/reporting/ReportingExample.cs index 1f93ad49..dceb88bd 100644 --- a/dotnet/reporting/ReportingExample.cs +++ b/dotnet/reporting/ReportingExample.cs @@ -27,6 +27,10 @@ namespace reporting } } + ReportControlBlock rcb = (ReportControlBlock) parameter; + + Console.WriteLine("Buffered: " + rcb.IsBuffered()); + } @@ -48,13 +52,14 @@ namespace reporting try { con.Connect (hostname, 102); - string rcbReference = "simpleIOGenericIO/LLN0.RP.EventsRCB"; + string rcbReference = "simpleIOGenericIO/LLN0.RP.EventsRCB01"; - ReportControlBlock rcb = con.getReportControlBlock(rcbReference); + ReportControlBlock rcb = con.GetReportControlBlock(rcbReference); rcb.GetRCBValues(); - rcb.InstallReportHandler(reportHandler, null); + // note: the second parameter is not required! + rcb.InstallReportHandler(reportHandler, rcb); if (rcb.IsBuffered()) Console.WriteLine ("RCB: " + rcbReference + " is buffered"); diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs index 35a78b9f..c5b03c02 100644 --- a/dotnet/tests/Test.cs +++ b/dotnet/tests/Test.cs @@ -15,6 +15,65 @@ namespace tests Assert.AreEqual (10.0f, val.ToFloat ()); } + + [Test ()] + public void MmsValueBitString () + { + var val = MmsValue.NewBitString(10); + + Assert.AreEqual (MmsType.MMS_BIT_STRING, val.GetType()); + Assert.AreEqual (10, val.Size()); + + val.BitStringFromUInt32(7); + + Assert.AreEqual(7, val.BitStringToUInt32()); + + Assert.AreEqual(true, val.GetBit(0)); + Assert.AreEqual(true, val.GetBit(1)); + Assert.AreEqual(true, val.GetBit(2)); + Assert.AreEqual(false, val.GetBit(3)); + + Assert.AreEqual(false, val.GetBit(9)); + + Assert.AreEqual(false, val.GetBit(10)); + + val.SetBit(3, true); + Assert.AreEqual(true, val.GetBit(3)); + + Assert.AreEqual(15, val.BitStringToUInt32()); + + val.SetBit(3, false); + Assert.AreEqual(7, val.BitStringToUInt32()); + } + + [Test()] + public void MmsValueOctetString () + { + var val = MmsValue.NewOctetString(20); + + Assert.AreEqual (0, val.Size()); + Assert.AreEqual (20, val.MaxSize()); + + byte[] octetString = val.getOctetString(); + + Assert.AreEqual (0, octetString.Length); + + octetString = new byte[5]; + octetString[0] = 0x11; + octetString[1] = 0x12; + octetString[2] = 0x13; + octetString[3] = 0x14; + octetString[4] = 0x15; + + val.setOctetString(octetString); + + Assert.AreEqual(5, val.Size()); + + byte[] secondOctetString = val.getOctetString(); + + Assert.AreEqual(octetString, secondOctetString); + } + } } diff --git a/dotnet/tests/tests.csproj b/dotnet/tests/tests.csproj index fffb7f87..76e97b72 100644 --- a/dotnet/tests/tests.csproj +++ b/dotnet/tests/tests.csproj @@ -21,7 +21,7 @@ false - full + none true bin\Release prompt @@ -30,7 +30,9 @@ - + + nunit + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 3c52875b..5bc51cf5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,7 +8,9 @@ add_subdirectory(server_example_control) add_subdirectory(server_example_dynamic) add_subdirectory(server_example_config_file) add_subdirectory(server_example_complex_array) +add_subdirectory(server_example_threadless) add_subdirectory(server_example_61400_25) +add_subdirectory(server_example_setting_groups) add_subdirectory(iec61850_client_example1) add_subdirectory(iec61850_client_example2) add_subdirectory(iec61850_client_example3) diff --git a/examples/Makefile b/examples/Makefile index e2168aef..1b83d6ac 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -21,6 +21,8 @@ EXAMPLE_DIRS += server_example_config_file EXAMPLE_DIRS += server_example_dynamic EXAMPLE_DIRS += server_example_complex_array EXAMPLE_DIRS += server_example_61400_25 +EXAMPLE_DIRS += server_example_threadless +EXAMPLE_DIRS += server_example_setting_groups EXAMPLE_DIRS += goose_subscriber EXAMPLE_DIRS += goose_publisher EXAMPLE_DIRS += mms_utility diff --git a/examples/goose_publisher/goose_publisher_example.c b/examples/goose_publisher/goose_publisher_example.c index 494fb497..47b0390a 100644 --- a/examples/goose_publisher/goose_publisher_example.c +++ b/examples/goose_publisher/goose_publisher_example.c @@ -23,11 +23,23 @@ main(int argc, char** argv) LinkedList_add(dataSetValues, MmsValue_newBinaryTime(false)); LinkedList_add(dataSetValues, MmsValue_newIntegerFromInt32(5678)); - GoosePublisher publisher = GoosePublisher_create(NULL, "eth0"); + CommParameters gooseCommParameters; - GoosePublisher_setGoCbRef(publisher, "Test1/LLN0$GO$gocb1"); + gooseCommParameters.appId = 1000; + gooseCommParameters.dstAddress[0] = 0x01; + gooseCommParameters.dstAddress[1] = 0x0c; + gooseCommParameters.dstAddress[2] = 0xcd; + gooseCommParameters.dstAddress[3] = 0x01; + gooseCommParameters.dstAddress[4] = 0x00; + gooseCommParameters.dstAddress[5] = 0x01; + gooseCommParameters.vlanId = 0; + gooseCommParameters.vlanPriority = 4; + + GoosePublisher publisher = GoosePublisher_create(&gooseCommParameters, "eth0"); + + GoosePublisher_setGoCbRef(publisher, "simpleIOGenericIO/LLN0$GO$gcbAnalogValues"); GoosePublisher_setConfRev(publisher, 1); - GoosePublisher_setDataSetRef(publisher, "Test1/LLN0$dataset1"); + GoosePublisher_setDataSetRef(publisher, "simpleIOGenericIO/LLN0$AnalogValues"); int i = 0; diff --git a/examples/goose_subscriber/goose_subscriber_example.c b/examples/goose_subscriber/goose_subscriber_example.c index 09fe5688..00fd888c 100644 --- a/examples/goose_subscriber/goose_subscriber_example.c +++ b/examples/goose_subscriber/goose_subscriber_example.c @@ -6,8 +6,8 @@ * Has to be started as root in Linux. */ -#include "goose_subscriber.h" -#include "thread.h" +#include "goose_receiver.h" +#include "hal_thread.h" #include #include @@ -28,7 +28,7 @@ gooseListener(GooseSubscriber subscriber, void* parameter) printf(" stNum: %u sqNum: %u\n", GooseSubscriber_getStNum(subscriber), GooseSubscriber_getSqNum(subscriber)); printf(" timeToLive: %u\n", GooseSubscriber_getTimeAllowedToLive(subscriber)); - printf(" timestamp: %"PRIu64"\n", GooseSubscriber_getTimestamp(subscriber)); + printf(" timestamp: %llu\n", GooseSubscriber_getTimestamp(subscriber)); MmsValue* values = GooseSubscriber_getDataSetValues(subscriber); @@ -50,20 +50,26 @@ main(int argc, char** argv) MmsValue_setElement(dataSetValues, i, dataSetEntry); } - // GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbEvents", dataSetValues); + GooseReceiver receiver = GooseReceiver_create(); - GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL); + if (argc > 1) { + printf("Set interface id: %s\n", argv[1]); + GooseReceiver_setInterfaceId(receiver, argv[1]); + } + else { + printf("Using interface eth0\n"); + GooseReceiver_setInterfaceId(receiver, "eth0"); + } - if (argc > 1) { - printf("Set interface id: %s\n", argv[1]); - GooseSubscriber_setInterfaceId(subscriber, argv[1]); - } + GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL); GooseSubscriber_setAppId(subscriber, 1000); GooseSubscriber_setListener(subscriber, gooseListener, NULL); - GooseSubscriber_subscribe(subscriber); + GooseReceiver_addSubscriber(receiver, subscriber); + + GooseReceiver_start(receiver); signal(SIGINT, sigint_handler); diff --git a/examples/iec61850_client_example1/client_example1.c b/examples/iec61850_client_example1/client_example1.c index fcd56d7f..b8429a09 100644 --- a/examples/iec61850_client_example1/client_example1.c +++ b/examples/iec61850_client_example1/client_example1.c @@ -9,7 +9,7 @@ #include #include -#include "thread.h" +#include "hal_thread.h" void reportCallbackFunction(void* parameter, ClientReport report) diff --git a/examples/iec61850_client_example2/client_example2.c b/examples/iec61850_client_example2/client_example2.c index c6d6cf26..d199d0ab 100644 --- a/examples/iec61850_client_example2/client_example2.c +++ b/examples/iec61850_client_example2/client_example2.c @@ -25,6 +25,8 @@ printDataDirectory(char* doRef, IedConnection con, int spaces) LinkedList dataAttributes = IedConnection_getDataDirectory(con, &error, doRef); + //LinkedList dataAttributes = IedConnection_getDataDirectoryByFC(con, &error, doRef, MX); + if (dataAttributes != NULL) { LinkedList dataAttribute = LinkedList_getNext(dataAttributes); @@ -70,7 +72,10 @@ main(int argc, char** argv) printf("Get logical device list...\n"); LinkedList deviceList = IedConnection_getLogicalDeviceList(con, &error); - printf("error: %i\n", error); + if (error != IED_ERROR_OK) { + printf("Failed to read device list (error code: %i)\n", error); + goto cleanup_and_exit; + } LinkedList device = LinkedList_getNext(deviceList); @@ -191,6 +196,7 @@ main(int argc, char** argv) printf("Connection failed!\n"); } +cleanup_and_exit: IedConnection_destroy(con); } diff --git a/examples/iec61850_client_example3/client_example3.c b/examples/iec61850_client_example3/client_example3.c index 93ab88df..6e8e0533 100644 --- a/examples/iec61850_client_example3/client_example3.c +++ b/examples/iec61850_client_example3/client_example3.c @@ -5,10 +5,27 @@ */ #include "iec61850_client.h" +#include "hal_thread.h" #include #include +static void commandTerminationHandler(void *parameter, ControlObjectClient connection) +{ + + + LastApplError lastApplError = ControlObjectClient_getLastApplError(connection); + + // if lastApplError.error != 0 this indicates a CommandTermination- + if (lastApplError.error != 0) { + printf("Received CommandTermination-.\n"); + printf(" LastApplError: %i\n", lastApplError.error); + printf(" addCause: %i\n", lastApplError.addCause); + } + else + printf("Received CommandTermination+.\n"); +} + int main(int argc, char** argv) { char* hostname; @@ -57,6 +74,7 @@ int main(int argc, char** argv) { if (error == IED_ERROR_OK) { bool state = MmsValue_getBoolean(stVal); + MmsValue_delete(stVal); printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state); } @@ -91,6 +109,101 @@ int main(int argc, char** argv) { ControlObjectClient_destroy(control); + /**************************************** + * Direct control with enhanced security + ****************************************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO3", con); + + ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL); + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO3 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO3\n"); + } + + MmsValue_delete(ctlVal); + + /* Wait for command termination message */ + Thread_sleep(1000); + + ControlObjectClient_destroy(control); + + /* Check if status value has changed */ + + stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", ST); + + if (error == IED_ERROR_OK) { + bool state = MmsValue_getBoolean(stVal); + + printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state); + + MmsValue_delete(stVal); + } + else { + printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n"); + } + + /*********************************************** + * Select before operate with enhanced security + ***********************************************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO4", con); + + ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL); + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_selectWithValue(control, ctlVal)) { + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO4 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO4!\n"); + } + + } + else { + printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n"); + } + + MmsValue_delete(ctlVal); + + /* Wait for command termination message */ + Thread_sleep(1000); + + ControlObjectClient_destroy(control); + + + /********************************************************************* + * Direct control with enhanced security (expect CommandTermination-) + *********************************************************************/ + + control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO9", con); + + ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL); + + ctlVal = MmsValue_newBoolean(true); + + if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) { + printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n"); + } + else { + printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n"); + } + + MmsValue_delete(ctlVal); + + /* Wait for command termination message */ + Thread_sleep(1000); + + ControlObjectClient_destroy(control); + IedConnection_close(con); } diff --git a/examples/iec61850_client_example4/client_example4.c b/examples/iec61850_client_example4/client_example4.c index 12cec16d..1b1d4619 100644 --- a/examples/iec61850_client_example4/client_example4.c +++ b/examples/iec61850_client_example4/client_example4.c @@ -11,7 +11,7 @@ #include #include -#include "thread.h" +#include "hal_thread.h" static void printDataSetValues(MmsValue* dataSet) diff --git a/examples/iec61850_client_example5/client_example5.c b/examples/iec61850_client_example5/client_example5.c index 4f43805a..f49c0aba 100644 --- a/examples/iec61850_client_example5/client_example5.c +++ b/examples/iec61850_client_example5/client_example5.c @@ -11,7 +11,7 @@ #include #include -#include "thread.h" +#include "hal_thread.h" int main(int argc, char** argv) { @@ -47,9 +47,12 @@ int main(int argc, char** argv) { // IsoConnectionParameters_setRemoteApTitle(parameters, NULL, 0); // IsoConnectionParameters_setLocalApTitle(parameters, NULL, 0); + TSelector localTSelector = { 3, { 0x00, 0x01, 0x02 } }; + TSelector remoteTSelector = { 2, { 0x00, 0x01 } }; + /* change parameters for presentation, session and transport layers */ - IsoConnectionParameters_setRemoteAddresses(parameters, 0x12345678, 12 , 13); - IsoConnectionParameters_setLocalAddresses(parameters, 0x87654321, 1234 , 2345); + IsoConnectionParameters_setRemoteAddresses(parameters, 0x12345678, 12, localTSelector); + IsoConnectionParameters_setLocalAddresses(parameters, 0x87654321, 1234 , remoteTSelector); char* password = "top secret"; @@ -61,6 +64,8 @@ int main(int argc, char** argv) { IsoConnectionParameters_setAcseAuthenticationParameter(parameters, auth); + IedConnection_setConnectTimeout(con, 10000); + /* call connect when all parameters are set */ IedConnection_connect(con, &error, hostname, tcpPort); diff --git a/examples/iec61850_client_example_files/client_example_files.c b/examples/iec61850_client_example_files/client_example_files.c index 36efa3fb..0b3f5f38 100644 --- a/examples/iec61850_client_example_files/client_example_files.c +++ b/examples/iec61850_client_example_files/client_example_files.c @@ -15,7 +15,7 @@ #include #include -#include "thread.h" +#include "hal_thread.h" #define MAX_BUFFER_SIZE 2000000 diff --git a/examples/iec61850_client_example_reporting/client_example_reporting.c b/examples/iec61850_client_example_reporting/client_example_reporting.c index e234b3c2..1c6f7a86 100644 --- a/examples/iec61850_client_example_reporting/client_example_reporting.c +++ b/examples/iec61850_client_example_reporting/client_example_reporting.c @@ -11,7 +11,7 @@ #include #include -#include "thread.h" +#include "hal_thread.h" static int running = 0; @@ -105,7 +105,7 @@ int main(int argc, char** argv) { /* Read RCB values */ ClientReportControlBlock rcb = - IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB", NULL); + IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL); if (error != IED_ERROR_OK) { printf("getRCBValues service error!\n"); @@ -131,7 +131,7 @@ int main(int argc, char** argv) { Thread_sleep(1000); - IedConnection_triggerGIReport(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB"); + IedConnection_triggerGIReport(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01"); if (error != IED_ERROR_OK) { printf("Error triggering a GI report (code: %i)\n", error); diff --git a/examples/mms_client_example1/mms_client_example1.c b/examples/mms_client_example1/mms_client_example1.c index ece6535b..d8ad47c6 100644 --- a/examples/mms_client_example1/mms_client_example1.c +++ b/examples/mms_client_example1/mms_client_example1.c @@ -27,7 +27,7 @@ #include #include #include "mms_client_connection.h" -#include "thread.h" +#include "hal_thread.h" int main(int argc, char** argv) { diff --git a/examples/server_example1/server_example1.c b/examples/server_example1/server_example1.c index 7d3e14fb..14a0b2a1 100644 --- a/examples/server_example1/server_example1.c +++ b/examples/server_example1/server_example1.c @@ -22,7 +22,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include diff --git a/examples/server_example1/static_model.c b/examples/server_example1/static_model.c index c3ac50db..3abfe08a 100644 --- a/examples/server_example1/static_model.c +++ b/examples/server_example1/static_model.c @@ -4,7 +4,7 @@ * automatically generated from sampleModel_with_dataset.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -148,7 +148,7 @@ extern DataSetEntry ds_Device1_LLN0_dataset1_fcda1; extern DataSetEntry ds_Device1_LLN0_dataset1_fcda2; DataSetEntry ds_Device1_LLN0_dataset1_fcda0 = { - "SampleIEDDevice1", + "Device1", "LLN0$ST$Mod$q", -1, NULL, @@ -157,7 +157,7 @@ DataSetEntry ds_Device1_LLN0_dataset1_fcda0 = { }; DataSetEntry ds_Device1_LLN0_dataset1_fcda1 = { - "SampleIEDDevice1", + "Device1", "MMXU1$ST$Mod$q", -1, NULL, @@ -166,7 +166,7 @@ DataSetEntry ds_Device1_LLN0_dataset1_fcda1 = { }; DataSetEntry ds_Device1_LLN0_dataset1_fcda2 = { - "SampleIEDDevice1", + "Device1", "MMXU1$CF$Mod$ctlModel", -1, NULL, @@ -175,7 +175,7 @@ DataSetEntry ds_Device1_LLN0_dataset1_fcda2 = { }; DataSet ds_Device1_LLN0_dataset1 = { - "SampleIEDDevice1", + "Device1", "LLN0$dataset1", 3, &ds_Device1_LLN0_dataset1_fcda0, @@ -184,7 +184,7 @@ DataSet ds_Device1_LLN0_dataset1 = { LogicalDevice iedModel_Device1 = { LogicalDeviceModelType, - "SampleIEDDevice1", + "Device1", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_Device1_LLN0 @@ -1718,31 +1718,9 @@ DataAttribute iedModel_Device1_MMXU2_TotW_t = { NULL, 0}; - extern ReportControlBlock iedModel_Device1_LLN0_report0; -ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep", "LLN0$RP$brcbEV1", true, "dataset1", 1, 9, 239, 50, 900000, NULL}; - - - - - - - - - - - - - - - - - - - - - +ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep01", "LLN0$RP$brcbEV1", true, "dataset1", 1, 9, 239, 50, 900000, NULL}; @@ -1753,6 +1731,7 @@ IedModel iedModel = { &ds_Device1_LLN0_dataset1, &iedModel_Device1_LLN0_report0, NULL, + NULL, initializeValues }; diff --git a/examples/server_example1/static_model.h b/examples/server_example1/static_model.h index 94afedd8..208787e3 100644 --- a/examples/server_example1/static_model.h +++ b/examples/server_example1/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_Device1; diff --git a/examples/server_example2/server_example2.c b/examples/server_example2/server_example2.c index 20fe7a6e..e4d95e90 100644 --- a/examples/server_example2/server_example2.c +++ b/examples/server_example2/server_example2.c @@ -22,7 +22,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include diff --git a/examples/server_example2/static_model.c b/examples/server_example2/static_model.c index 6eeed2f0..fbc3cfa7 100644 --- a/examples/server_example2/static_model.c +++ b/examples/server_example2/static_model.c @@ -1,10 +1,10 @@ /* * static_model.c * - * automatically generated from complexModel.scd + * automatically generated from complexModel.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -314,7 +314,7 @@ extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda3; extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda4; DataSetEntry ds_Inverter_LLN0_dataset1_fcda0 = { - "ied1Inverter", + "Inverter", "LLN0$ST$Mod$q", -1, NULL, @@ -323,7 +323,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda0 = { }; DataSetEntry ds_Inverter_LLN0_dataset1_fcda1 = { - "ied1Battery", + "Battery", "LLN0$ST$Mod$q", -1, NULL, @@ -332,7 +332,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda1 = { }; DataSetEntry ds_Inverter_LLN0_dataset1_fcda2 = { - "ied1Inverter", + "Inverter", "MMXU1$ST$Mod$q", -1, NULL, @@ -341,7 +341,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda2 = { }; DataSetEntry ds_Inverter_LLN0_dataset1_fcda3 = { - "ied1Inverter", + "Inverter", "MMXU1$CF$Mod$ctlModel", -1, NULL, @@ -350,7 +350,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda3 = { }; DataSetEntry ds_Inverter_LLN0_dataset1_fcda4 = { - "ied1Inverter", + "Inverter", "MMXU1$MX$TotW$mag", -1, NULL, @@ -359,7 +359,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda4 = { }; DataSet ds_Inverter_LLN0_dataset1 = { - "ied1Inverter", + "Inverter", "LLN0$dataset1", 5, &ds_Inverter_LLN0_dataset1_fcda0, @@ -368,7 +368,7 @@ DataSet ds_Inverter_LLN0_dataset1 = { LogicalDevice iedModel_Inverter = { LogicalDeviceModelType, - "ied1Inverter", + "Inverter", (ModelNode*) &iedModel, (ModelNode*) &iedModel_Battery, (ModelNode*) &iedModel_Inverter_LLN0 @@ -2480,7 +2480,7 @@ DataAttribute iedModel_Inverter_MMXU1_W_phsC_t = { LogicalDevice iedModel_Battery = { LogicalDeviceModelType, - "ied1Battery", + "Battery", (ModelNode*) &iedModel, (ModelNode*) &iedModel_Physical_Measurements, (ModelNode*) &iedModel_Battery_LLN0 @@ -3512,7 +3512,7 @@ DataAttribute iedModel_Battery_ZBTC1_ChaA_t = { LogicalDevice iedModel_Physical_Measurements = { LogicalDeviceModelType, - "ied1Physical_Measurements", + "Physical_Measurements", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_Physical_Measurements_LLN0 @@ -3870,47 +3870,9 @@ DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t = { NULL, 0}; - extern ReportControlBlock iedModel_Inverter_LLN0_report0; -ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb1", "ID", false, "dataset1", 0, 3, 32, 0, 0, NULL}; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb101", "ID", false, "dataset1", 0, 3, 32, 0, 0, NULL}; @@ -3921,6 +3883,7 @@ IedModel iedModel = { &ds_Inverter_LLN0_dataset1, &iedModel_Inverter_LLN0_report0, NULL, + NULL, initializeValues }; diff --git a/examples/server_example2/static_model.h b/examples/server_example2/static_model.h index 609fc245..34623f80 100644 --- a/examples/server_example2/static_model.h +++ b/examples/server_example2/static_model.h @@ -1,14 +1,14 @@ /* * static_model.h * - * automatically generated from complexModel.scd + * automatically generated from complexModel.icd */ #ifndef STATIC_MODEL_H_ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_Inverter; diff --git a/examples/server_example3/server_example3.c b/examples/server_example3/server_example3.c index e7659369..0953e409 100644 --- a/examples/server_example3/server_example3.c +++ b/examples/server_example3/server_example3.c @@ -6,7 +6,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include @@ -66,6 +66,16 @@ controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) return true; } + +static void +connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter) +{ + if (connected) + printf("Connection opened\n"); + else + printf("Connection closed\n"); +} + int main(int argc, char** argv) { @@ -89,6 +99,8 @@ main(int argc, char** argv) (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO4); + IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, 102); @@ -135,4 +147,5 @@ main(int argc, char** argv) /* Cleanup - free all resources */ IedServer_destroy(iedServer); + } /* main() */ diff --git a/examples/server_example3/static_model.c b/examples/server_example3/static_model.c index ced6aaeb..90017480 100644 --- a/examples/server_example3/static_model.c +++ b/examples/server_example3/static_model.c @@ -4,7 +4,7 @@ * automatically generated from simpleIO_direct_control.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -160,7 +160,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO1$stVal", -1, NULL, @@ -169,7 +169,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO2$stVal", -1, NULL, @@ -178,7 +178,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO3$stVal", -1, NULL, @@ -187,7 +187,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO4$stVal", -1, NULL, @@ -196,7 +196,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { }; DataSet ds_GenericIO_LLN0_Events = { - "simpleIOGenericIO", + "GenericIO", "LLN0$Events", 4, &ds_GenericIO_LLN0_Events_fcda0, @@ -209,7 +209,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda2; extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda3; DataSetEntry ds_GenericIO_LLN0_Events2_fcda0 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO1", -1, NULL, @@ -218,7 +218,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda0 = { }; DataSetEntry ds_GenericIO_LLN0_Events2_fcda1 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO2", -1, NULL, @@ -227,7 +227,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda1 = { }; DataSetEntry ds_GenericIO_LLN0_Events2_fcda2 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO3", -1, NULL, @@ -236,7 +236,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda2 = { }; DataSetEntry ds_GenericIO_LLN0_Events2_fcda3 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO4", -1, NULL, @@ -245,7 +245,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda3 = { }; DataSet ds_GenericIO_LLN0_Events2 = { - "simpleIOGenericIO", + "GenericIO", "LLN0$Events2", 4, &ds_GenericIO_LLN0_Events2_fcda0, @@ -254,7 +254,7 @@ DataSet ds_GenericIO_LLN0_Events2 = { LogicalDevice iedModel_GenericIO = { LogicalDeviceModelType, - "simpleIOGenericIO", + "GenericIO", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_GenericIO_LLN0 @@ -1973,13 +1973,12 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { NULL, 0}; - extern ReportControlBlock iedModel_GenericIO_LLN0_report0; extern ReportControlBlock iedModel_GenericIO_LLN0_report1; extern ReportControlBlock iedModel_GenericIO_LLN0_report2; extern ReportControlBlock iedModel_GenericIO_LLN0_report3; -ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1}; ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2}; ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3}; ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 8, 111, 50, 1000, NULL}; @@ -1987,21 +1986,13 @@ ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, - - - - - - - - - IedModel iedModel = { "simpleIO", &iedModel_GenericIO, &ds_GenericIO_LLN0_Events, &iedModel_GenericIO_LLN0_report0, NULL, + NULL, initializeValues }; diff --git a/examples/server_example3/static_model.h b/examples/server_example3/static_model.h index 6883b430..b5670e9f 100644 --- a/examples/server_example3/static_model.h +++ b/examples/server_example3/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_GenericIO; diff --git a/examples/server_example4/server_example4.c b/examples/server_example4/server_example4.c index e09ffee9..166515e1 100644 --- a/examples/server_example4/server_example4.c +++ b/examples/server_example4/server_example4.c @@ -16,7 +16,7 @@ #include "iec61850_server.h" #include "static_model.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include diff --git a/examples/server_example4/static_model.c b/examples/server_example4/static_model.c index 4cb637a6..08974481 100644 --- a/examples/server_example4/static_model.c +++ b/examples/server_example4/static_model.c @@ -4,7 +4,7 @@ * automatically generated from simpleIO_direct_control.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -158,7 +158,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO1$stVal", -1, NULL, @@ -167,7 +167,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO2$stVal", -1, NULL, @@ -176,7 +176,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO3$stVal", -1, NULL, @@ -185,7 +185,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO4$stVal", -1, NULL, @@ -194,7 +194,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { }; DataSet ds_GenericIO_LLN0_Events = { - "simpleIOGenericIO", + "GenericIO", "LLN0$Events", 4, &ds_GenericIO_LLN0_Events_fcda0, @@ -203,7 +203,7 @@ DataSet ds_GenericIO_LLN0_Events = { LogicalDevice iedModel_GenericIO = { LogicalDeviceModelType, - "simpleIOGenericIO", + "GenericIO", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_GenericIO_LLN0 @@ -1909,19 +1909,9 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { NULL, 0}; - extern ReportControlBlock iedModel_GenericIO_LLN0_report0; -ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL}; - - - - - - - - - +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL}; @@ -1932,6 +1922,7 @@ IedModel iedModel = { &ds_GenericIO_LLN0_Events, &iedModel_GenericIO_LLN0_report0, NULL, + NULL, initializeValues }; diff --git a/examples/server_example4/static_model.h b/examples/server_example4/static_model.h index 4f352309..58dd28b5 100644 --- a/examples/server_example4/static_model.h +++ b/examples/server_example4/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_GenericIO; diff --git a/examples/server_example5/server_example5.c b/examples/server_example5/server_example5.c index 2f31f96b..58931db2 100644 --- a/examples/server_example5/server_example5.c +++ b/examples/server_example5/server_example5.c @@ -22,7 +22,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include diff --git a/examples/server_example5/static_model.c b/examples/server_example5/static_model.c index 4cb637a6..08974481 100644 --- a/examples/server_example5/static_model.c +++ b/examples/server_example5/static_model.c @@ -4,7 +4,7 @@ * automatically generated from simpleIO_direct_control.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -158,7 +158,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO1$stVal", -1, NULL, @@ -167,7 +167,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO2$stVal", -1, NULL, @@ -176,7 +176,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO3$stVal", -1, NULL, @@ -185,7 +185,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO4$stVal", -1, NULL, @@ -194,7 +194,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { }; DataSet ds_GenericIO_LLN0_Events = { - "simpleIOGenericIO", + "GenericIO", "LLN0$Events", 4, &ds_GenericIO_LLN0_Events_fcda0, @@ -203,7 +203,7 @@ DataSet ds_GenericIO_LLN0_Events = { LogicalDevice iedModel_GenericIO = { LogicalDeviceModelType, - "simpleIOGenericIO", + "GenericIO", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_GenericIO_LLN0 @@ -1909,19 +1909,9 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { NULL, 0}; - extern ReportControlBlock iedModel_GenericIO_LLN0_report0; -ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL}; - - - - - - - - - +ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL}; @@ -1932,6 +1922,7 @@ IedModel iedModel = { &ds_GenericIO_LLN0_Events, &iedModel_GenericIO_LLN0_report0, NULL, + NULL, initializeValues }; diff --git a/examples/server_example5/static_model.h b/examples/server_example5/static_model.h index 4f352309..58dd28b5 100644 --- a/examples/server_example5/static_model.h +++ b/examples/server_example5/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_GenericIO; diff --git a/examples/server_example_61400_25/server_example_61400_25.c b/examples/server_example_61400_25/server_example_61400_25.c index c86e153b..890b5a3d 100644 --- a/examples/server_example_61400_25/server_example_61400_25.c +++ b/examples/server_example_61400_25/server_example_61400_25.c @@ -22,7 +22,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include diff --git a/examples/server_example_61400_25/static_model.c b/examples/server_example_61400_25/static_model.c index 1a8e22de..d40302fc 100644 --- a/examples/server_example_61400_25/static_model.c +++ b/examples/server_example_61400_25/static_model.c @@ -4,7 +4,7 @@ * automatically generated from wtur.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -344,7 +344,7 @@ extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs; LogicalDevice iedModel_WTG = { LogicalDeviceModelType, - "WINDWTG", + "WTG", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_WTG_LLN0 @@ -4466,22 +4466,13 @@ DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs = { - - - - - - - - - - IedModel iedModel = { "WIND", &iedModel_WTG, NULL, NULL, NULL, + NULL, initializeValues }; diff --git a/examples/server_example_61400_25/static_model.h b/examples/server_example_61400_25/static_model.h index 171dba6f..c19af1c4 100644 --- a/examples/server_example_61400_25/static_model.h +++ b/examples/server_example_61400_25/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_WTG; diff --git a/examples/server_example_complex_array/server_example_ca.c b/examples/server_example_complex_array/server_example_ca.c index bad2b47e..5db5a755 100644 --- a/examples/server_example_complex_array/server_example_ca.c +++ b/examples/server_example_complex_array/server_example_ca.c @@ -5,7 +5,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include diff --git a/examples/server_example_complex_array/static_model.c b/examples/server_example_complex_array/static_model.c index 07b6e111..979e8d35 100644 --- a/examples/server_example_complex_array/static_model.c +++ b/examples/server_example_complex_array/static_model.c @@ -4,7 +4,7 @@ * automatically generated from mhai_array.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -58,7 +58,7 @@ extern DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency; LogicalDevice iedModel_ComplexArray = { LogicalDeviceModelType, - "testComplexArray", + "ComplexArray", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_ComplexArray_LLN0 @@ -589,12 +589,14 @@ DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency = { + IedModel iedModel = { "test", &iedModel_ComplexArray, NULL, NULL, NULL, + NULL, initializeValues }; diff --git a/examples/server_example_complex_array/static_model.h b/examples/server_example_complex_array/static_model.h index bad70b71..0999d581 100644 --- a/examples/server_example_complex_array/static_model.h +++ b/examples/server_example_complex_array/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_ComplexArray; diff --git a/examples/server_example_config_file/server_example_config_file.c b/examples/server_example_config_file/server_example_config_file.c index 11320ccc..924707bc 100644 --- a/examples/server_example_config_file/server_example_config_file.c +++ b/examples/server_example_config_file/server_example_config_file.c @@ -15,13 +15,13 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include -#include "filesystem.h" -#include "config_file_parser.h" +#include "hal_filesystem.h" +#include "iec61850_config_file_parser.h" static int running = 0; diff --git a/examples/server_example_config_file/vmd-filestore/model.cfg b/examples/server_example_config_file/vmd-filestore/model.cfg index 4b7698a3..d0507a1f 100644 --- a/examples/server_example_config_file/vmd-filestore/model.cfg +++ b/examples/server_example_config_file/vmd-filestore/model.cfg @@ -1,6 +1,7 @@ -MODEL{ -LD(simpleIOGenericIO){ +MODEL(simpleIO){ +LD(GenericIO){ LN(LLN0){ +SG(1 2) DO(Mod 0){ DA(q 0 23 0 2 0); DA(t 0 22 0 0 0); @@ -35,8 +36,8 @@ DE(GGIO1$MX$AnIn2); DE(GGIO1$MX$AnIn3); DE(GGIO1$MX$AnIn4); } -RC(EventsRCB Events 0 Events 1 8 111 50 1000); -RC(AnalogValuesRCB AnalogValues 0 AnalogValues 1 8 111 50 1000); +RC(EventsRCB01 - 0 Events 1 8 111 50 1000); +RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 8 111 50 1000); GC(gcbEvents events Events 2 0){ PA(4 111 1000 010ccd010001); } diff --git a/examples/server_example_control/server_example_control.c b/examples/server_example_control/server_example_control.c index 202606ac..72fc6bc2 100644 --- a/examples/server_example_control/server_example_control.c +++ b/examples/server_example_control/server_example_control.c @@ -5,7 +5,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include @@ -44,23 +44,31 @@ checkHandler(void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) return CONTROL_ACCEPTED; + if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO9) + return CONTROL_ACCEPTED; + return CONTROL_OBJECT_UNDEFINED; } -void +static ControlHandlerResult controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) { if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); - if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) + else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); - if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) + else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); - if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) + else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); + + else + return CONTROL_RESULT_FAILED; + + return CONTROL_RESULT_OK; } int @@ -91,7 +99,16 @@ main(int argc, char** argv) /* this is optional - performs operative checks */ IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, checkHandler, - IEDMODEL_GenericIO_GGIO1_SPCSO4); + IEDMODEL_GenericIO_GGIO1_SPCSO4); + + + IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO9, + (ControlHandler) controlHandlerForBinaryOutput, + IEDMODEL_GenericIO_GGIO1_SPCSO9); + + /* this is optional - performs operative checks */ + IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO9, checkHandler, + IEDMODEL_GenericIO_GGIO1_SPCSO9); /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, 102); diff --git a/examples/server_example_control/simpleIO_control_tests.icd b/examples/server_example_control/simpleIO_control_tests.icd index 63c13eae..6bfd88cd 100644 --- a/examples/server_example_control/simpleIO_control_tests.icd +++ b/examples/server_example_control/simpleIO_control_tests.icd @@ -93,6 +93,11 @@ sbo-with-enhanced-security + + + direct-with-enhanced-security + + @@ -127,6 +132,7 @@ + diff --git a/examples/server_example_control/static_model.c b/examples/server_example_control/static_model.c index f9040c3e..50e3df5d 100644 --- a/examples/server_example_control/static_model.c +++ b/examples/server_example_control/static_model.c @@ -4,7 +4,7 @@ * automatically generated from simpleIO_control_tests.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -277,6 +277,28 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal; extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q; extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t; extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO9; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel; extern DataObject iedModel_GenericIO_GGIO1_Ind1; extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; @@ -298,7 +320,7 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; LogicalDevice iedModel_GenericIO = { LogicalDeviceModelType, - "simpleIOGenericIO", + "GenericIO", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_GenericIO_LLN0 @@ -3195,7 +3217,7 @@ DataObject iedModel_GenericIO_GGIO1_SPCSO8 = { DataObjectModelType, "SPCSO8", (ModelNode*) &iedModel_GenericIO_GGIO1, - (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw, 0 }; @@ -3681,6 +3703,288 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel = { NULL, 0}; +DataObject iedModel_GenericIO_GGIO1_SPCSO9 = { + DataObjectModelType, + "SPCSO9", + (ModelNode*) &iedModel_GenericIO_GGIO1, + (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + 0 +}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper = { + DataAttributeModelType, + "Oper", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal, + 0, + CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin, + NULL, + 0, + CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat, + 0, + CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent, + NULL, + 0, + CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin, + NULL, + NULL, + 0, + CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_T, + NULL, + 0, + CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test, + NULL, + 0, + CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check, + NULL, + 0, + CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check = { + DataAttributeModelType, + "Check", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper, + NULL, + NULL, + 0, + CO, + CHECK, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel = { + DataAttributeModelType, + "Cancel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_stVal, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal, + 0, + CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal = { + DataAttributeModelType, + "ctlVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin, + NULL, + 0, + CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin = { + DataAttributeModelType, + "origin", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat, + 0, + CO, + CONSTRUCTED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat = { + DataAttributeModelType, + "orCat", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent, + NULL, + 0, + CO, + ENUMERATED, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent = { + DataAttributeModelType, + "orIdent", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin, + NULL, + NULL, + 0, + CO, + OCTET_STRING_64, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum = { + DataAttributeModelType, + "ctlNum", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T, + NULL, + 0, + CO, + INT8U, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T = { + DataAttributeModelType, + "T", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test, + NULL, + 0, + CO, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test = { + DataAttributeModelType, + "Test", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel, + NULL, + NULL, + 0, + CO, + BOOLEAN, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal = { + DataAttributeModelType, + "stVal", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_q, + NULL, + 0, + ST, + BOOLEAN, + 0 + TRG_OPT_DATA_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q = { + DataAttributeModelType, + "q", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_t, + NULL, + 0, + ST, + QUALITY, + 0 + TRG_OPT_QUALITY_CHANGED, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t = { + DataAttributeModelType, + "t", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_ctlModel, + NULL, + 0, + ST, + TIMESTAMP, + 0, + NULL, + 0}; + +DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel = { + DataAttributeModelType, + "ctlModel", + (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9, + NULL, + NULL, + 0, + CF, + ENUMERATED, + 0, + NULL, + 0}; + DataObject iedModel_GenericIO_GGIO1_Ind1 = { DataObjectModelType, "Ind1", @@ -3878,22 +4182,13 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = { - - - - - - - - - - IedModel iedModel = { "simpleIO", &iedModel_GenericIO, NULL, NULL, NULL, + NULL, initializeValues }; @@ -3920,4 +4215,6 @@ iedModel_GenericIO_GGIO1_SPCSO6_ctlModel.mmsValue = MmsValue_newIntegerFromInt32 iedModel_GenericIO_GGIO1_SPCSO7_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); iedModel_GenericIO_GGIO1_SPCSO8_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(4); + +iedModel_GenericIO_GGIO1_SPCSO9_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3); } diff --git a/examples/server_example_control/static_model.h b/examples/server_example_control/static_model.h index e93a2bc3..67c3967f 100644 --- a/examples/server_example_control/static_model.h +++ b/examples/server_example_control/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_GenericIO; @@ -280,6 +280,28 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal; extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q; extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t; extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel; +extern DataObject iedModel_GenericIO_GGIO1_SPCSO9; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t; +extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel; extern DataObject iedModel_GenericIO_GGIO1_Ind1; extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal; extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q; @@ -568,6 +590,28 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t; #define IEDMODEL_GenericIO_GGIO1_SPCSO8_q (&iedModel_GenericIO_GGIO1_SPCSO8_q) #define IEDMODEL_GenericIO_GGIO1_SPCSO8_t (&iedModel_GenericIO_GGIO1_SPCSO8_t) #define IEDMODEL_GenericIO_GGIO1_SPCSO8_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO8_ctlModel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9 (&iedModel_GenericIO_GGIO1_SPCSO9) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper (&iedModel_GenericIO_GGIO1_SPCSO9_Oper) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_stVal (&iedModel_GenericIO_GGIO1_SPCSO9_stVal) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_q (&iedModel_GenericIO_GGIO1_SPCSO9_q) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_t (&iedModel_GenericIO_GGIO1_SPCSO9_t) +#define IEDMODEL_GenericIO_GGIO1_SPCSO9_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO9_ctlModel) #define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1) #define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal) #define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q) diff --git a/examples/server_example_dynamic/server_example_dynamic.c b/examples/server_example_dynamic/server_example_dynamic.c index 361acd0f..49dccbc1 100644 --- a/examples/server_example_dynamic/server_example_dynamic.c +++ b/examples/server_example_dynamic/server_example_dynamic.c @@ -6,7 +6,7 @@ */ #include "iec61850_server.h" -#include "thread.h" +#include "hal_thread.h" #include #include #include @@ -40,6 +40,8 @@ int main(int argc, char** argv) { DataObject* lln0_mod = CDC_ENS_create("Mod", (ModelNode*) lln0, 0); DataObject* lln0_health = CDC_ENS_create("Health", (ModelNode*) lln0, 0); + SettingGroupControlBlock_create(lln0, 1, 1); + /* Add a temperature sensor LN */ LogicalNode* ttmp1 = LogicalNode_create("TTMP1", lDevice1); DataObject* ttmp1_tmpsv = CDC_SAV_create("TmpSv", (ModelNode*) ttmp1, 0, false); diff --git a/examples/server_example_goose/server_example_goose.c b/examples/server_example_goose/server_example_goose.c index 7df535ce..f014c42b 100644 --- a/examples/server_example_goose/server_example_goose.c +++ b/examples/server_example_goose/server_example_goose.c @@ -7,7 +7,7 @@ */ #include "iec61850_server.h" -#include "thread.h" /* for Thread_sleep() */ +#include "hal_thread.h" /* for Thread_sleep() */ #include #include #include diff --git a/examples/server_example_goose/simpleIO_direct_control_goose.icd b/examples/server_example_goose/simpleIO_direct_control_goose.icd index 81357b14..5f68fa01 100644 --- a/examples/server_example_goose/simpleIO_direct_control_goose.icd +++ b/examples/server_example_goose/simpleIO_direct_control_goose.icd @@ -17,7 +17,7 @@
-

111

+

1

4

01-0c-cd-01-00-01

1000

@@ -25,7 +25,7 @@
-

111

+

1

4

01-0c-cd-01-00-01

1000

diff --git a/examples/server_example_goose/static_model.c b/examples/server_example_goose/static_model.c index 1295dfe1..2beaeac0 100644 --- a/examples/server_example_goose/static_model.c +++ b/examples/server_example_goose/static_model.c @@ -4,7 +4,7 @@ * automatically generated from simpleIO_direct_control_goose.icd */ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; static void initializeValues(); @@ -159,7 +159,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2; extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3; DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO1$stVal", -1, NULL, @@ -168,7 +168,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO2$stVal", -1, NULL, @@ -177,7 +177,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO3$stVal", -1, NULL, @@ -186,7 +186,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = { }; DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$ST$SPCSO4$stVal", -1, NULL, @@ -195,7 +195,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = { }; DataSet ds_GenericIO_LLN0_Events = { - "simpleIOGenericIO", + "GenericIO", "LLN0$Events", 4, &ds_GenericIO_LLN0_Events_fcda0, @@ -208,7 +208,7 @@ extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2; extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3; DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda0 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$MX$AnIn1", -1, NULL, @@ -217,7 +217,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda0 = { }; DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda1 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$MX$AnIn2", -1, NULL, @@ -226,7 +226,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda1 = { }; DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$MX$AnIn3", -1, NULL, @@ -235,7 +235,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2 = { }; DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3 = { - "simpleIOGenericIO", + "GenericIO", "GGIO1$MX$AnIn4", -1, NULL, @@ -244,7 +244,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3 = { }; DataSet ds_GenericIO_LLN0_AnalogValues = { - "simpleIOGenericIO", + "GenericIO", "LLN0$AnalogValues", 4, &ds_GenericIO_LLN0_AnalogValues_fcda0, @@ -253,7 +253,7 @@ DataSet ds_GenericIO_LLN0_AnalogValues = { LogicalDevice iedModel_GenericIO = { LogicalDeviceModelType, - "simpleIOGenericIO", + "GenericIO", (ModelNode*) &iedModel, NULL, (ModelNode*) &iedModel_GenericIO_LLN0 @@ -1970,7 +1970,7 @@ extern GSEControlBlock iedModel_GenericIO_LLN0_gse1; static PhyComAddress iedModel_GenericIO_LLN0_gse0_address = { 4, - 111, + 1, 1000, {0x1, 0xc, 0xcd, 0x1, 0x0, 0x1} }; @@ -1979,7 +1979,7 @@ GSEControlBlock iedModel_GenericIO_LLN0_gse0 = {&iedModel_GenericIO_LLN0, "gcbEv static PhyComAddress iedModel_GenericIO_LLN0_gse1_address = { 4, - 111, + 1, 1000, {0x1, 0xc, 0xcd, 0x1, 0x0, 0x1} }; @@ -1987,12 +1987,14 @@ static PhyComAddress iedModel_GenericIO_LLN0_gse1_address = { GSEControlBlock iedModel_GenericIO_LLN0_gse1 = {&iedModel_GenericIO_LLN0, "gcbAnalogValues", "analog", "AnalogValues", 2, false,&iedModel_GenericIO_LLN0_gse1_address, NULL}; + IedModel iedModel = { "simpleIO", &iedModel_GenericIO, &ds_GenericIO_LLN0_Events, &iedModel_GenericIO_LLN0_report0, &iedModel_GenericIO_LLN0_gse0, + NULL, initializeValues }; diff --git a/examples/server_example_goose/static_model.h b/examples/server_example_goose/static_model.h index 5a4bb9b2..5e827db7 100644 --- a/examples/server_example_goose/static_model.h +++ b/examples/server_example_goose/static_model.h @@ -8,7 +8,7 @@ #define STATIC_MODEL_H_ #include -#include "model.h" +#include "iec61850_model.h" extern IedModel iedModel; extern LogicalDevice iedModel_GenericIO; diff --git a/make/stack_includes.mk b/make/stack_includes.mk index 6d89ad10..28e1291c 100644 --- a/make/stack_includes.mk +++ b/make/stack_includes.mk @@ -1,24 +1,9 @@ INCLUDES = -I$(LIBIEC_HOME)/config -INCLUDES += -I$(LIBIEC_HOME)/src/common -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_presentation -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_session -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_cotp -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_acse -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_mms/common -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_mms/client -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_mms/server -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_client -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_common -INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_server +INCLUDES += -I$(LIBIEC_HOME)/src/common/inc +INCLUDES += -I$(LIBIEC_HOME)/src/mms/inc +INCLUDES += -I$(LIBIEC_HOME)/src/mms/inc_private INCLUDES += -I$(LIBIEC_HOME)/src/mms/asn1 -INCLUDES += -I$(LIBIEC_HOME)/src/iedcommon -INCLUDES += -I$(LIBIEC_HOME)/src/iedserver/mms_mapping -INCLUDES += -I$(LIBIEC_HOME)/src/iedserver/model -INCLUDES += -I$(LIBIEC_HOME)/src/iedserver -INCLUDES += -I$(LIBIEC_HOME)/src/iedclient -INCLUDES += -I$(LIBIEC_HOME)/src/hal -INCLUDES += -I$(LIBIEC_HOME)/src/hal/thread -INCLUDES += -I$(LIBIEC_HOME)/src/hal/socket -INCLUDES += -I$(LIBIEC_HOME)/src/hal/filesystem -INCLUDES += -I$(LIBIEC_HOME)/src/hal/time +INCLUDES += -I$(LIBIEC_HOME)/src/iec61850/inc +INCLUDES += -I$(LIBIEC_HOME)/src/iec61850/inc_private +INCLUDES += -I$(LIBIEC_HOME)/src/hal/inc INCLUDES += -I$(LIBIEC_HOME)/src/goose diff --git a/make/target_system.mk b/make/target_system.mk index 161acd90..c7edf351 100644 --- a/make/target_system.mk +++ b/make/target_system.mk @@ -4,7 +4,7 @@ MIPSEL_TOOLCHAIN_PREFIX=mipsel-openwrt-linux- # ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabihf- #ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi- #ARM_TOOLCHAIN_PREFIX=arm-poky-linux-gnueabi- -ARM_TOOLCHAIN_PREFIX=arm-linux- +ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi- UCLINUX_ARM_TOOLCHAIN_PREFIX=arm-uclinux-elf- MINGW_TOOLCHAIN_PREFIX=i586-mingw32msvc- #MINGW_TOOLCHAIN_PREFIX=x86_64-w64-mingw32- @@ -126,7 +126,7 @@ LIB_OBJS_DIR = $(LIBIEC_HOME)/build endif CFLAGS += -g -CFLAGS += -Os +#CFLAGS += -Os DYNLIB_LDFLAGS=-lpthread endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 19d94212..46dbfae8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,12 +5,12 @@ set (lib_common_SRCS ./common/map.c ./common/linked_list.c ./common/byte_buffer.c +./common/lib_memory.c ./common/string_utilities.c ./common/buffer_chain.c ./common/conversions.c ./common/mem_alloc_linked_list.c ./common/simple_allocator.c -./common/byte_stream.c ./mms/iso_server/iso_connection.c ./mms/iso_server/iso_server.c ./mms/iso_acse/acse.c @@ -52,24 +52,25 @@ set (lib_common_SRCS ./mms/asn1/asn1_ber_primitive_value.c ./mms/asn1/ber_encoder.c ./mms/asn1/ber_integer.c -./mms/iso_client/impl/iso_client_connection.c +./mms/iso_client/iso_client_connection.c ./mms/iso_common/iso_connection_parameters.c ./mms/iso_session/iso_session.c -./iedclient/impl/client_control.c -./iedclient/impl/client_report_control.c -./iedclient/impl/client_report.c -./iedclient/impl/ied_connection.c -./iedcommon/iec61850_common.c -./iedserver/impl/ied_server.c -./iedserver/impl/client_connection.c -./iedserver/model/model.c -./iedserver/model/dynamic_model.c -./iedserver/model/cdc.c -./iedserver/model/config_file_parser.c -./iedserver/mms_mapping/control.c -./iedserver/mms_mapping/mms_mapping.c -./iedserver/mms_mapping/reporting.c -./iedserver/mms_mapping/mms_goose.c +./iec61850/client/client_control.c +./iec61850/client/client_report_control.c +./iec61850/client/client_goose_control.c +./iec61850/client/client_report.c +./iec61850/client/ied_connection.c +./iec61850/common/iec61850_common.c +./iec61850/server/impl/ied_server.c +./iec61850/server/impl/client_connection.c +./iec61850/server/model/model.c +./iec61850/server/model/dynamic_model.c +./iec61850/server/model/cdc.c +./iec61850/server/model/config_file_parser.c +./iec61850/server/mms_mapping/control.c +./iec61850/server/mms_mapping/mms_mapping.c +./iec61850/server/mms_mapping/reporting.c +./iec61850/server/mms_mapping/mms_goose.c ) @@ -168,6 +169,7 @@ set (lib_asn1c_SRCS set (lib_goose_SRCS ./goose/goose_subscriber.c +./goose/goose_receiver.c ./goose/goose_publisher.c ) @@ -274,8 +276,6 @@ set_target_properties(iec61850-shared PROPERTIES ) - - GENERATE_EXPORT_HEADER(iec61850-shared BASE_NAME iec61850-shared EXPORT_MACRO_NAME iec61850-shared_EXPORT @@ -286,12 +286,21 @@ GENERATE_EXPORT_HEADER(iec61850-shared add_library (iec61850 STATIC ${library_SRCS}) IF(UNIX) -target_link_libraries (iec61850 - -lpthread - -lm -) + IF (CONFIG_SYSTEM_HAS_CLOCK_GETTIME) + target_link_libraries (iec61850 + -lpthread + -lm + -lrt + ) + ELSE () + target_link_libraries (iec61850 + -lpthread + -lm + ) + ENDIF (CONFIG_SYSTEM_HAS_CLOCK_GETTIME) ENDIF(UNIX) + iF(WITH_WPCAP) target_link_libraries(iec61850 ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/lib/wpcap.lib @@ -318,6 +327,8 @@ if(MSVC) endif() ENDIF(WITH_WPCAP) + + install (TARGETS iec61850 iec61850-shared RUNTIME DESTINATION bin ARCHIVE DESTINATION lib diff --git a/src/common/buffer_chain.c b/src/common/buffer_chain.c index 39253be2..96043140 100644 --- a/src/common/buffer_chain.c +++ b/src/common/buffer_chain.c @@ -42,7 +42,7 @@ BufferChain_destroy(BufferChain self) while (currentChainElement != NULL) { BufferChain nextChainElement = currentChainElement->nextPart; - free(currentChainElement); + GLOBAL_FREEMEM(currentChainElement); currentChainElement = nextChainElement; } } diff --git a/src/common/byte_buffer.c b/src/common/byte_buffer.c index 96949611..9c1a4f9d 100644 --- a/src/common/byte_buffer.c +++ b/src/common/byte_buffer.c @@ -28,10 +28,10 @@ ByteBuffer* ByteBuffer_create(ByteBuffer* self, int maxSize) { if (self == NULL) { - self = (ByteBuffer*) calloc(1, sizeof(ByteBuffer)); + self = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); } - self->buffer = (uint8_t*) calloc(maxSize, sizeof(uint8_t)); + self->buffer = (uint8_t*) GLOBAL_CALLOC(maxSize, sizeof(uint8_t)); self->maxSize = maxSize; self->size = 0; @@ -41,8 +41,8 @@ ByteBuffer_create(ByteBuffer* self, int maxSize) void ByteBuffer_destroy(ByteBuffer* self) { - free(self->buffer); - free(self); + GLOBAL_FREEMEM(self->buffer); + GLOBAL_FREEMEM(self); } void @@ -105,6 +105,7 @@ ByteBuffer_setSize(ByteBuffer* self, int size) return self->size; } +#if 0 void ByteBuffer_print(ByteBuffer* self, char* message) { @@ -119,3 +120,4 @@ ByteBuffer_print(ByteBuffer* self, char* message) } printf("\n"); } +#endif diff --git a/src/common/lib_memory.c b/src/common/lib_memory.c new file mode 100644 index 00000000..d279b6c0 --- /dev/null +++ b/src/common/lib_memory.c @@ -0,0 +1,83 @@ +/* + * lib_memory.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "lib_memory.h" + +static MemoryExceptionHandler exceptionHandler = NULL; +static void* exceptionHandlerParameter = NULL; + +static void +noMemoryAvailableHandler(void) +{ + if (exceptionHandler != NULL) + exceptionHandler(exceptionHandlerParameter); +} + +void +Memory_installExceptionHandler(MemoryExceptionHandler handler, void* parameter) +{ + exceptionHandler = handler; + exceptionHandlerParameter = parameter; +} + +void* +Memory_malloc(size_t size) +{ + void* memory = malloc(size); + + if (memory == NULL) + noMemoryAvailableHandler(); + + return memory; +} + + +void* +Memory_calloc(size_t nmemb, size_t size) +{ + void* memory = calloc(nmemb, size); + + if (memory == NULL) + noMemoryAvailableHandler(); + + return memory; +} + + +void * +Memory_realloc(void *ptr, size_t size) +{ + void* memory = realloc(ptr, size); + + if (memory == NULL) + noMemoryAvailableHandler(); + + return memory; +} + +void +Memory_free(void* memb) +{ + free(memb); +} + diff --git a/src/common/linked_list.c b/src/common/linked_list.c index 93dd0436..a487b097 100644 --- a/src/common/linked_list.c +++ b/src/common/linked_list.c @@ -1,7 +1,7 @@ /* * linked_list.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -38,7 +38,7 @@ LinkedList_create() { LinkedList newList; - newList = (LinkedList) malloc(sizeof(struct sLinkedList)); + newList = (LinkedList) GLOBAL_MALLOC(sizeof(struct sLinkedList)); newList->data = NULL; newList->next = NULL; @@ -57,9 +57,11 @@ LinkedList_destroyDeep(LinkedList list, LinkedListValueDeleteFunction valueDelet do { currentElement = nextElement; nextElement = currentElement->next; + if (currentElement->data != NULL) valueDeleteFunction(currentElement->data); - free(currentElement); + + GLOBAL_FREEMEM(currentElement); } while (nextElement != NULL); } @@ -67,7 +69,7 @@ LinkedList_destroyDeep(LinkedList list, LinkedListValueDeleteFunction valueDelet void LinkedList_destroy(LinkedList list) { - LinkedList_destroyDeep(list, free); + LinkedList_destroyDeep(list, Memory_free); } /** @@ -82,7 +84,7 @@ LinkedList_destroyStatic(LinkedList list) do { currentElement = nextElement; nextElement = currentElement->next; - free(currentElement); + GLOBAL_FREEMEM(currentElement); } while (nextElement != NULL); } @@ -123,7 +125,7 @@ LinkedList_remove(LinkedList list, void* data) while (currentElement != NULL) { if (currentElement->data == data) { lastElement->next = currentElement->next; - free(currentElement); + GLOBAL_FREEMEM(currentElement); return true; } diff --git a/src/common/map.c b/src/common/map.c index c1fe97b2..d0ab9e33 100644 --- a/src/common/map.c +++ b/src/common/map.c @@ -42,7 +42,7 @@ comparePointerKeys(void* key1, void* key2) Map Map_create() { - Map map = (Map) calloc(1, sizeof(struct sMap)); + Map map = (Map) GLOBAL_CALLOC(1, sizeof(struct sMap)); map->entries = LinkedList_create(); map->compareKeys = comparePointerKeys; return map; @@ -57,7 +57,7 @@ Map_size(Map map) void* Map_addEntry(Map map, void* key, void* value) { - MapEntry* entry = (MapEntry*) malloc(sizeof(MapEntry)); + MapEntry* entry = (MapEntry*) GLOBAL_MALLOC(sizeof(MapEntry)); entry->key = key; entry->value = value; LinkedList_add(map->entries, entry); @@ -81,9 +81,9 @@ Map_removeEntry(Map map, void* key, bool deleteKey) value = entry->value; if (deleteKey == true) - free(entry->key); - free(entry); - free(element); + GLOBAL_FREEMEM(entry->key); + GLOBAL_FREEMEM(entry); + GLOBAL_FREEMEM(element); break; } @@ -117,12 +117,12 @@ Map_delete(Map map, bool deleteKey) while ((element = LinkedList_getNext(element)) != NULL) { MapEntry* entry = (MapEntry*) element->data; if (deleteKey == true) - free(entry->key); - free(entry->value); + GLOBAL_FREEMEM(entry->key); + GLOBAL_FREEMEM(entry->value); } LinkedList_destroy(map->entries); - free(map); + GLOBAL_FREEMEM(map); } void @@ -133,12 +133,12 @@ Map_deleteStatic(Map map, bool deleteKey) if (deleteKey == true) { while ((element = LinkedList_getNext(element)) != NULL) { MapEntry* entry = (MapEntry*) element->data; - free(entry->key); + GLOBAL_FREEMEM(entry->key); } } LinkedList_destroy(map->entries); - free(map); + GLOBAL_FREEMEM(map); } void @@ -150,10 +150,10 @@ Map_deleteDeep(Map map, bool deleteKey, void while ((element = LinkedList_getNext(element)) != NULL) { MapEntry* entry = (MapEntry*) element->data; if (deleteKey == true) - free(entry->key); + GLOBAL_FREEMEM(entry->key); valueDeleteFunction(entry->value); } LinkedList_destroy(map->entries); - free(map); + GLOBAL_FREEMEM(map); } diff --git a/src/common/simple_allocator.c b/src/common/simple_allocator.c index 6e0fac08..6592f746 100644 --- a/src/common/simple_allocator.c +++ b/src/common/simple_allocator.c @@ -1,7 +1,7 @@ /* * simple_allocator.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -33,9 +33,20 @@ MemoryAllocator_init(MemoryAllocator* self, char* memoryBlock, int size) self->size = size; } +static int +getAlignedSize(int size) +{ + if ((size % sizeof(void*)) > 0) + return sizeof(void*) * ((size + sizeof(void*)) / sizeof(void*)); + else + return size; +} + char* MemoryAllocator_allocate(MemoryAllocator* self, int size) { + size = getAlignedSize(size); + if (((self->currentPtr - self->memoryBlock) + size) <= self->size) { char* ptr = self->currentPtr; self->currentPtr += size; diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c index 98dfd29b..702f9453 100644 --- a/src/common/string_utilities.c +++ b/src/common/string_utilities.c @@ -28,7 +28,7 @@ copySubString(char* startPos, char* endPos) { int newStringLength = endPos - startPos; - char* newString = (char*) malloc(newStringLength) + 1; + char* newString = (char*) GLOBAL_MALLOC(newStringLength) + 1; memcpy(newString, startPos, newStringLength); @@ -42,7 +42,7 @@ copyString(const char* string) { int newStringLength = strlen(string) + 1; - char* newString = (char*) malloc(newStringLength); + char* newString = (char*) GLOBAL_MALLOC(newStringLength); memcpy(newString, string, newStringLength); @@ -50,7 +50,7 @@ copyString(const char* string) } char* -copyStringToBuffer(char* string, char* buffer) +copyStringToBuffer(const char* string, char* buffer) { int newStringLength = strlen(string) + 1; @@ -63,7 +63,7 @@ copyStringToBuffer(char* string, char* buffer) char* createStringFromBuffer(uint8_t* buf, int size) { - char* newStr = (char*) malloc(size + 1); + char* newStr = (char*) GLOBAL_MALLOC(size + 1); memcpy(newStr, buf, size); newStr[size] = 0; @@ -110,7 +110,7 @@ createString(int count, ...) } va_end(ap); - newStr = (char*) malloc(newStringLength + 1); + newStr = (char*) GLOBAL_MALLOC(newStringLength + 1); currentPos = newStr; diff --git a/src/doxygen.config b/src/doxygen.config index 81704c69..84558522 100644 --- a/src/doxygen.config +++ b/src/doxygen.config @@ -16,9 +16,9 @@ DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "libIEC61850 0.7.8" +PROJECT_NAME = "libIEC61850" -PROJECT_NUMBER = +PROJECT_NUMBER = 0.8.2 PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE server and client library" @@ -207,29 +207,31 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = "iedclient/iec61850_client.h" -INPUT += "mms/iso_mms/common/mms_value.h" -INPUT += "common/linked_list.h" +INPUT = "iec61850/inc/iec61850_client.h" +INPUT += "mms/inc/mms_value.h" +INPUT += "common/inc/linked_list.h" INPUT += "doxygen/mainpage.doxygen" -INPUT += "iedserver/iec61850_server.h" -INPUT += "iedcommon/iec61850_common.h" -INPUT += "iedserver/model/model.h" -INPUT += "iedserver/model/dynamic_model.h" -INPUT += "iedserver/model/config_file_parser.h" -INPUT += "iedserver/model/cdc.h" +INPUT += "iec61850/inc/iec61850_server.h" +INPUT += "iec61850/inc/iec61850_common.h" +INPUT += "iec61850/inc/iec61850_model.h" +INPUT += "iec61850/inc/iec61850_dynamic_model.h" +INPUT += "iec61850/inc/iec61850_config_file_parser.h" +INPUT += "iec61850/inc/iec61850_cdc.h" INPUT += "goose/goose_subscriber.h" -INPUT += "mms/iso_mms/server/mms_device_model.h" -INPUT += "mms/iso_mms/common/mms_types.h" -INPUT += "mms/iso_mms/server/mms_server.h" -INPUT += "mms/iso_server/iso_server.h" -INPUT += "mms/iso_mms/server/mms_named_variable_list.h" -INPUT += "mms/iso_mms/client/mms_client_connection.h" -INPUT += "mms/iso_client/iso_connection_parameters.h" -INPUT += "hal/socket/socket.h" -INPUT += "hal/thread/thread.h" -INPUT += "hal/ethernet/ethernet.h" -INPUT += "hal/filesystem/filesystem.h" -INPUT += "hal/hal.h" +INPUT += "mms/inc/mms_device_model.h" +INPUT += "mms/inc/mms_types.h" +INPUT += "mms/inc/mms_server.h" +INPUT += "mms/inc/iso_server.h" +INPUT += "mms/inc/mms_named_variable_list.h" +INPUT += "mms/inc/mms_type_spec.h" +INPUT += "mms/inc/mms_types.h" +INPUT += "mms/inc/mms_client_connection.h" +INPUT += "mms/inc/iso_connection_parameters.h" +INPUT += "hal/inc/hal_socket.h" +INPUT += "hal/inc/hal_thread.h" +INPUT += "hal/inc/hal_ethernet.h" +INPUT += "hal/inc/hal_filesystem.h" +INPUT += "hal/inc/hal_time.h" INPUT_ENCODING = UTF-8 diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c index a4090c9c..371fde2e 100644 --- a/src/goose/goose_publisher.c +++ b/src/goose/goose_publisher.c @@ -24,11 +24,15 @@ #include "libiec61850_platform_includes.h" #include "stack_config.h" #include "goose_publisher.h" -#include "ethernet.h" +#include "hal_ethernet.h" #include "ber_encoder.h" #include "mms_server_internal.h" #include "mms_value_internal.h" +#ifndef DEBUG_GOOSE_PUBLISHER +#define DEBUG_GOOSE_PUBLISHER 0 +#endif + #define GOOSE_MAX_MESSAGE_SIZE 1518 static void @@ -36,7 +40,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, char* interf struct sGoosePublisher { uint8_t* buffer; - uint16_t appId; + //uint16_t appId; EthernetSocket ethernetSocket; int lengthField; int payloadStart; @@ -45,9 +49,9 @@ struct sGoosePublisher { char* goCBRef; char* dataSetRef; - uint16_t minTime; - uint16_t maxTime; - bool fixedOffs; + //uint16_t minTime; + //uint16_t maxTime; + //bool fixedOffs; uint32_t confRev; uint32_t stNum; @@ -63,7 +67,7 @@ struct sGoosePublisher { GoosePublisher GoosePublisher_create(CommParameters* parameters, char* interfaceID) { - GoosePublisher self = (GoosePublisher) calloc(1, sizeof(struct sGoosePublisher)); + GoosePublisher self = (GoosePublisher) GLOBAL_CALLOC(1, sizeof(struct sGoosePublisher)); prepareGooseBuffer(self, parameters, interfaceID); @@ -82,16 +86,16 @@ GoosePublisher_destroy(GoosePublisher self) MmsValue_delete(self->timestamp); if (self->goID != NULL) - free(self->goID); + GLOBAL_FREEMEM(self->goID); if (self->goCBRef != NULL) - free(self->goCBRef); + GLOBAL_FREEMEM(self->goCBRef); if (self->dataSetRef != NULL) - free(self->dataSetRef); + GLOBAL_FREEMEM(self->dataSetRef); - free(self->buffer); - free(self); + GLOBAL_FREEMEM(self->buffer); + GLOBAL_FREEMEM(self); } void @@ -190,7 +194,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, char* interf else self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr); - self->buffer = (uint8_t*) malloc(GOOSE_MAX_MESSAGE_SIZE); + self->buffer = (uint8_t*) GLOBAL_MALLOC(GOOSE_MAX_MESSAGE_SIZE); memcpy(self->buffer, dstAddr, 6); memcpy(self->buffer + 6, srcAddr, 6); @@ -246,6 +250,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe if (self->goID != NULL) goosePduLength += BerEncoder_determineEncodedStringSize(self->goID); + else + goosePduLength += BerEncoder_determineEncodedStringSize(self->goCBRef); uint32_t timeAllowedToLive = self->timeAllowedToLive; @@ -303,6 +309,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe /* Encode goID */ if (self->goID != NULL) bufPos = BerEncoder_encodeStringWithTag(0x83, self->goID, buffer, bufPos); + else + bufPos = BerEncoder_encodeStringWithTag(0x83, self->goCBRef, buffer, bufPos); /* Encode t */ bufPos = BerEncoder_encodeOctetString(0x84, self->timestamp->value.utcTime, 8, buffer, bufPos); @@ -363,6 +371,9 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet) self->buffer[lengthIndex] = gooseLength / 256; self->buffer[lengthIndex + 1] = gooseLength & 0xff; + if (DEBUG_GOOSE_PUBLISHER) + printf("GOOSE_PUBLISHER: send GOOSE message\n"); + Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + payloadLength); return 0; diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c new file mode 100644 index 00000000..0b5e39d6 --- /dev/null +++ b/src/goose/goose_receiver.c @@ -0,0 +1,778 @@ +/* + * goose_receiver.c + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" +#include "goose_subscriber.h" +#include "hal_ethernet.h" +#include "hal_thread.h" + +#include "ber_decode.h" + +#include "mms_value.h" +#include "mms_value_internal.h" +#include "linked_list.h" + +#include "goose_receiver.h" +#include "goose_receiver_internal.h" + +#ifndef DEBUG_GOOSE_SUBSCRIBER +#define DEBUG_GOOSE_SUBSCRIBER 0 +#endif + +#define ETH_BUFFER_LENGTH 1518 + +#define ETH_P_GOOSE 0x88b8 + +struct sGooseReceiver { + bool running; + char* interfaceId; + uint8_t* buffer; + EthernetSocket ethSocket; + LinkedList subscriberList; +}; + + +GooseReceiver +GooseReceiver_create() +{ + GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver)); + + if (self != NULL) { + self->running = false; + self->interfaceId = NULL; + self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH); + self->ethSocket = NULL; + self->subscriberList = LinkedList_create(); + } + + return self; +} + +void +GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber) +{ + LinkedList_add(self->subscriberList, (void*) subscriber); +} + +void +GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber) +{ + LinkedList_remove(self->subscriberList, (void*) subscriber); +} + + +void +GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId) +{ + if (self->interfaceId != NULL) + GLOBAL_FREEMEM(self->interfaceId); + + self->interfaceId = copyString(interfaceId); +} + + +void +GooseReceiver_setBackupListener(GooseReceiver self) +{ +} + +static void +createNewStringFromBufferElement(MmsValue* value, uint8_t* bufferSrc, int elementLength) +{ + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(elementLength + 1); + memcpy(value->value.visibleString.buf, bufferSrc, elementLength); + value->value.visibleString.buf[elementLength] = 0; + value->value.visibleString.size = elementLength; +} + +static int +parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) +{ + int bufPos = 0; + int elementLength = 0; + + int elementIndex = 0; + + int maxIndex = MmsValue_getArraySize(dataSetValues) - 1; + + while (bufPos < allDataLength) { + uint8_t tag = buffer[bufPos++]; + + if (elementIndex > maxIndex) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: too much elements!\n"); + return 0; + } + + MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex); + + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + + if (bufPos + elementLength > allDataLength) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + return 0; + } + + switch (tag) { + case 0x80: /* reserved for access result */ + printf("GOOSE_SUBSCRIBER: found reserved value (tag 0x80)!\n"); + break; + case 0xa1: /* array */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); + if (MmsValue_getType(value) == MMS_ARRAY) { + if (!parseAllData(buffer + bufPos, elementLength, value)) + return -1; + } + break; + case 0xa2: /* structure */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); + if (MmsValue_getType(value) == MMS_STRUCTURE) { + if (!parseAllData(buffer + bufPos, elementLength, value)) + return -1; + } + break; + case 0x83: /* boolean */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n"); + + if (MmsValue_getType(value) == MMS_BOOLEAN) { + MmsValue_setBoolean(value, BerDecoder_decodeBoolean(buffer, bufPos)); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: message contains value of wrong type!\n"); + + break; + + case 0x84: /* BIT STRING */ + if (MmsValue_getType(value) == MMS_BIT_STRING) { + int padding = buffer[bufPos]; + int bitStringLength = (8 * (elementLength - 1)) - padding; + if (bitStringLength == value->value.bitString.size) { + memcpy(value->value.bitString.buf, buffer + bufPos + 1, + elementLength - 1); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) + printf("bit-string is of wrong size"); + } + break; + case 0x85: /* integer */ + if (MmsValue_getType(value) == MMS_INTEGER) { + if (elementLength <= value->value.integer->maxSize) { + value->value.integer->size = elementLength; + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + } + } + break; + case 0x86: /* unsigned integer */ + if (MmsValue_getType(value) == MMS_UNSIGNED) { + if (elementLength <= value->value.integer->maxSize) { + value->value.integer->size = elementLength; + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + } + } + break; + case 0x87: /* Float */ + if (MmsValue_getType(value) == MMS_FLOAT) { + if (elementLength == 9) { + MmsValue_setDouble(value, BerDecoder_decodeDouble(buffer, bufPos)); + } + else if (elementLength == 5) { + MmsValue_setFloat(value, BerDecoder_decodeFloat(buffer, bufPos)); + } + } + break; + + case 0x89: /* octet string */ + if (MmsValue_getType(value) == MMS_OCTET_STRING) { + if (elementLength <= value->value.octetString.maxSize) { + value->value.octetString.size = elementLength; + memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); + } + } + break; + case 0x8a: /* visible string */ + if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { + + if (value->value.visibleString.buf != NULL) { + if ((int32_t) value->value.visibleString.size >= elementLength) { + memcpy(value->value.visibleString.buf, buffer + bufPos, elementLength); + value->value.visibleString.buf[elementLength] = 0; + } + else { + GLOBAL_FREEMEM(value->value.visibleString.buf); + + createNewStringFromBufferElement(value, buffer + bufPos, elementLength); + } + } + else + createNewStringFromBufferElement(value, buffer + bufPos, elementLength); + + } + break; + case 0x8c: /* binary time */ + if (MmsValue_getType(value) == MMS_BINARY_TIME) { + if ((elementLength == 4) || (elementLength == 6)) { + memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); + } + } + break; + case 0x91: /* Utctime */ + if (elementLength == 8) { + if (MmsValue_getType(value) == MMS_UTC_TIME) { + MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: message contains value of wrong type!\n"); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); + break; + default: + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); + break; + } + + bufPos += elementLength; + + elementIndex++; + } + + return 1; +} + +static MmsValue* +parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure) +{ + int bufPos = 0; + int elementLength = 0; + + int elementIndex = 0; + + MmsValue* dataSetValues = NULL; + + while (bufPos < allDataLength) { + uint8_t tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + + if (bufPos + elementLength > allDataLength) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + goto exit_with_error; + } + + switch (tag) { + case 0x80: /* reserved for access result */ + break; + case 0xa1: /* array */ + break; + case 0xa2: /* structure */ + break; + case 0x83: /* boolean */ + break; + case 0x84: /* BIT STRING */ + break; + case 0x85: /* integer */ + break; + case 0x86: /* unsigned integer */ + break; + case 0x87: /* Float */ + break; + case 0x89: /* octet string */ + break; + case 0x8a: /* visible string */ + break; + case 0x8c: /* binary time */ + break; + case 0x91: /* Utctime */ + break; + default: + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); + goto exit_with_error; + } + + bufPos += elementLength; + + elementIndex++; + } + + if (isStructure) + dataSetValues = MmsValue_createEmptyStructure(elementIndex); + else + dataSetValues = MmsValue_createEmtpyArray(elementIndex); + + elementIndex = 0; + bufPos = 0; + + while (bufPos < allDataLength) { + uint8_t tag = buffer[bufPos++]; + + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + + if (bufPos + elementLength > allDataLength) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + goto exit_with_error; + } + + MmsValue* value = NULL; + + switch (tag) { + case 0xa1: /* array */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); + + value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false); + + if (value == NULL) + goto exit_with_error; + + break; + case 0xa2: /* structure */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); + + value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true); + + if (value == NULL) + goto exit_with_error; + + break; + case 0x83: /* boolean */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n"); + value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos)); + + break; + + case 0x84: /* BIT STRING */ + { + int padding = buffer[bufPos]; + int bitStringLength = (8 * (elementLength - 1)) - padding; + value = MmsValue_newBitString(bitStringLength); + memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); + + } + break; + case 0x85: /* integer */ + value = MmsValue_newInteger(elementLength * 8); + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + break; + case 0x86: /* unsigned integer */ + value = MmsValue_newUnsigned(elementLength * 8); + memcpy(value->value.integer->octets, buffer + bufPos, elementLength); + break; + case 0x87: /* Float */ + if (elementLength == 9) + value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos)); + else if (elementLength == 5) + value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos)); + break; + + case 0x89: /* octet string */ + value = MmsValue_newOctetString(elementLength, elementLength); + memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); + break; + case 0x8a: /* visible string */ + value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength); + break; + case 0x8c: /* binary time */ + if (elementLength == 4) + value = MmsValue_newBinaryTime(true); + else if (elementLength == 6) + value = MmsValue_newBinaryTime(false); + + if ((elementLength == 4) || (elementLength == 6)) + memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); + + break; + case 0x91: /* Utctime */ + if (elementLength == 8) { + value = MmsValue_newUtcTime(0); + MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); + } + else + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); + break; + default: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); + goto exit_with_error; + } + + bufPos += elementLength; + + if (value != NULL) { + MmsValue_setElement(dataSetValues, elementIndex, value); + elementIndex++; + } + } + + self->dataSetValuesSelfAllocated = true; + + return dataSetValues; + +exit_with_error: + + if (dataSetValues != NULL) + MmsValue_delete(dataSetValues); + + return NULL; +} + + +static int +parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) +{ + int bufPos = 0; + uint32_t timeAllowedToLive = 0; + uint32_t stNum = 0; + uint32_t sqNum = 0; + uint32_t confRev; + bool simulation = false; + bool ndsCom = false; + GooseSubscriber matchingSubscriber = NULL; + uint8_t* timestampBufPos = NULL; + uint8_t* dataSetBufferAddress = NULL; + int dataSetBufferLength = 0; + + uint32_t numberOfDatSetEntries = 0; + + if (buffer[bufPos++] == 0x61) { + int gooseLength; + bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); + + int gooseEnd = bufPos + gooseLength; + + while (bufPos < gooseEnd) { + int elementLength; + + uint8_t tag = buffer[bufPos++]; + bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); + + if (bufPos + elementLength > apduLength) { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); + + goto exit_with_fault; + } + + if (bufPos == -1) + goto exit_with_fault; + + switch(tag) { + case 0x80: /* gocbRef */ + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found gocbRef\n"); + + { + LinkedList element = LinkedList_getNext(self->subscriberList); + + while (element != NULL) { + GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); + + if (subscriber->goCBRefLen == elementLength) { + if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n"); + matchingSubscriber = subscriber; + break; + } + } + + element = LinkedList_getNext(element); + } + + if (matchingSubscriber == NULL) + return 0; + } + + break; + + case 0x81: /* timeAllowedToLive */ + + timeAllowedToLive = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timeAllowedToLive %u\n", timeAllowedToLive); + + break; + + case 0x82: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found dataSet\n"); + break; + + case 0x83: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found goId\n"); + break; + + case 0x84: + timestampBufPos = buffer + bufPos; + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timestamp\n"); + break; + + case 0x85: + stNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found stNum: %u\n", stNum); + break; + + case 0x86: + sqNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found sqNum: %u\n", sqNum); + break; + + case 0x87: + simulation = BerDecoder_decodeBoolean(buffer, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found simulation: %i\n", simulation); + break; + + case 0x88: + confRev = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found confRev: %u\n", confRev); + break; + + case 0x89: + ndsCom = BerDecoder_decodeBoolean(buffer, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found ndsCom: %i\n", ndsCom); + break; + + case 0x8a: + numberOfDatSetEntries = BerDecoder_decodeUint32(buffer, elementLength, bufPos); + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found number of entries: %u\n", numberOfDatSetEntries); + break; + + case 0xab: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found all data with length: %i\n", elementLength); + dataSetBufferAddress = buffer + bufPos; + dataSetBufferLength = elementLength; + break; + + default: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Unknown tag %02x\n", tag); + break; + } + + bufPos += elementLength; + } + + if (matchingSubscriber != NULL) { + + matchingSubscriber->timeAllowedToLive = timeAllowedToLive; + matchingSubscriber->confRev = confRev; + matchingSubscriber->ndsCom = ndsCom; + matchingSubscriber->simulation = simulation; + MmsValue_setUtcTimeByBuffer(matchingSubscriber->timestamp, timestampBufPos); + + if (matchingSubscriber->dataSetValues == NULL) + matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false); + else + parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues); + + bool isValid = true; + + if (matchingSubscriber->stNum == stNum) { + if (matchingSubscriber->sqNum >= sqNum) { + isValid = false; + } + } + + matchingSubscriber->stateValid = isValid; + + matchingSubscriber->stNum = stNum; + matchingSubscriber->sqNum = sqNum; + + matchingSubscriber->invalidityTime = Hal_getTimeInMs() + timeAllowedToLive; + + if (matchingSubscriber->listener != NULL) + matchingSubscriber->listener(matchingSubscriber, matchingSubscriber->listenerParameter); + + return 1; + } + + return 0; + } + +exit_with_fault: + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Invalid goose payload\n"); + return -1; +} + + +static void +parseGooseMessage(GooseReceiver self, int numbytes) +{ + int bufPos; + bool subscriberFound = false; + uint8_t* buffer = self->buffer; + + if (numbytes < 22) return; + + /* skip ethernet addresses */ + bufPos = 12; + int headerLength = 14; + + /* check for VLAN tag */ + if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) { + bufPos += 4; /* skip VLAN tag */ + headerLength += 4; + } + + /* check for GOOSE Ethertype */ + if (buffer[bufPos++] != 0x88) + return; + if (buffer[bufPos++] != 0xb8) + return; + + uint16_t appId; + + appId = buffer[bufPos++] * 0x100; + appId += buffer[bufPos++]; + + uint16_t length; + + length = buffer[bufPos++] * 0x100; + length += buffer[bufPos++]; + + /* skip reserved fields */ + bufPos += 4; + + int apduLength = length - 8; + + if (numbytes != length + headerLength) { + if (DEBUG) + printf("GOOSE_SUBSCRIBER: Invalid PDU size\n"); + return; + } + + if (DEBUG_GOOSE_SUBSCRIBER) { + printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n"); + printf("GOOSE_SUBSCRIBER: APPID: %u\n", appId); + printf("GOOSE_SUBSCRIBER: LENGTH: %u\n", length); + printf("GOOSE_SUBSCRIBER: APDU length: %i\n", apduLength); + } + + + // check if there is an interested subscriber + LinkedList element = LinkedList_getNext(self->subscriberList); + + while (element != NULL) { + GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); + + if (subscriber->appId == appId) { + subscriberFound = true; + break; + } + + element = LinkedList_getNext(element); + } + + if (subscriberFound) + parseGoosePayload(self, buffer + bufPos, apduLength); + else { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: GOOSE message ignored due to unknown APPID value\n"); + } +} + + +static void +gooseReceiverLoop(void* threadParameter) +{ + GooseReceiver self = (GooseReceiver) threadParameter; + + GooseReceiver_startThreadless(self); + + while (self->running) { + + GooseReceiver_tick(self); + + Thread_sleep(1); + } + + GooseReceiver_stopThreadless(self); +} + + +// start GOOSE receiver in a separate thread +void +GooseReceiver_start(GooseReceiver self) +{ + Thread thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, true); + + if (thread != NULL) { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: GOOSE receiver started for interface %s\n", self->interfaceId); + + Thread_start(thread); + } + else { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: Starting GOOSE receiver failed for interface %s\n", self->interfaceId); + } + +} + +void +GooseReceiver_stop(GooseReceiver self) +{ + self->running = false; +} + +void +GooseReceiver_destroy(GooseReceiver self) +{ + LinkedList_destroyDeep(self->subscriberList, + (LinkedListValueDeleteFunction) GooseSubscriber_destroy); + + GLOBAL_FREEMEM(self->buffer); + GLOBAL_FREEMEM(self); +} + +/*************************************** + * Functions for non-threaded operation + ***************************************/ +void +GooseReceiver_startThreadless(GooseReceiver self) +{ + + if (self->interfaceId == NULL) + self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); + else + self->ethSocket = Ethernet_createSocket(self->interfaceId, NULL); + + Ethernet_setProtocolFilter(self->ethSocket, ETH_P_GOOSE); + + self->running = true; +} + +void +GooseReceiver_stopThreadless(GooseReceiver self) +{ + Ethernet_destroySocket(self->ethSocket); + + self->running = false; +} + +// call after reception of ethernet frame and periodically to to house keeping tasks +void +GooseReceiver_tick(GooseReceiver self) +{ + int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); + + if (packetSize > 0) + parseGooseMessage(self, packetSize); +} diff --git a/src/goose/goose_receiver.h b/src/goose/goose_receiver.h new file mode 100644 index 00000000..c57f1d72 --- /dev/null +++ b/src/goose/goose_receiver.h @@ -0,0 +1,70 @@ +/* + * goose_receiver.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef GOOSE_RECEIVER_H_ +#define GOOSE_RECEIVER_H_ + +#include + +typedef struct sGooseReceiver* GooseReceiver; + +GooseReceiver +GooseReceiver_create(void); + +void +GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId); + +void +GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber); + +void +GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber); + +// call backup listener if message is not handled by a subscriber +void +GooseReceiver_setBackupListener(GooseReceiver self); + +// start GOOSE receiver in a separate thread +void +GooseReceiver_start(GooseReceiver self); + +void +GooseReceiver_stop(GooseReceiver self); + +void +GooseReceiver_destroy(GooseReceiver self); + +/*************************************** + * Functions for non-threaded operation + ***************************************/ +void +GooseReceiver_startThreadless(GooseReceiver self); + +void +GooseReceiver_stopThreadless(GooseReceiver self); + +// call after reception of ethernet frame and periodically to to house keeping tasks +void +GooseReceiver_tick(GooseReceiver self); + +#endif /* GOOSE_RECEIVER_H_ */ diff --git a/src/goose/goose_receiver_internal.h b/src/goose/goose_receiver_internal.h new file mode 100644 index 00000000..e595da00 --- /dev/null +++ b/src/goose/goose_receiver_internal.h @@ -0,0 +1,62 @@ +/* + * goose_receiver_internal.h + * + * Copyright 2014 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#ifndef GOOSE_RECEIVER_INTERNAL_H_ +#define GOOSE_RECEIVER_INTERNAL_H_ + + +#define ETH_BUFFER_LENGTH 1518 + +#define ETH_P_GOOSE 0x88b8 + +#ifndef DEBUG_GOOSE_SUBSCRIBER +#define DEBUG_GOOSE_SUBSCRIBER 0 +#endif + + +struct sGooseSubscriber { + char* goCBRef; + int goCBRefLen; + uint32_t timeAllowedToLive; + uint32_t stNum; + uint32_t sqNum; + uint32_t confRev; + MmsValue* timestamp; + bool simulation; + bool ndsCom; + + uint64_t invalidityTime; + bool stateValid; + + int32_t appId; /* APPID or -1 if APPID should be ignored */ + + MmsValue* dataSetValues; + bool dataSetValuesSelfAllocated; + + GooseListener listener; + void* listenerParameter; +}; + + + +#endif /* GOOSE_RECEIVER_INTERNAL_H_ */ diff --git a/src/goose/goose_subscriber.c b/src/goose/goose_subscriber.c index ff615087..f1d1e8ea 100644 --- a/src/goose/goose_subscriber.c +++ b/src/goose/goose_subscriber.c @@ -25,622 +25,20 @@ #include "stack_config.h" #include "goose_subscriber.h" -#include "ethernet.h" -#include "thread.h" +#include "hal_ethernet.h" +#include "hal_thread.h" #include "ber_decode.h" #include "mms_value.h" #include "mms_value_internal.h" -#define ETH_BUFFER_LENGTH 1518 - -#define ETH_P_GOOSE 0x88b8 - -struct sGooseSubscriber { - char* goCBRef; - int goCBRefLen; - uint32_t timeAllowedToLive; - uint32_t stNum; - uint32_t sqNum; - uint32_t confRev; - MmsValue* timestamp; - bool simulation; - bool ndsCom; - - int32_t appId; /* APPID or -1 if APPID should be ignored */ - - MmsValue* dataSetValues; - bool dataSetValuesSelfAllocated; - - GooseListener listener; - void* listenerParameter; - bool running; - Thread receiver; - char* interfaceId; -}; - -static void -createNewStringFromBufferElement(MmsValue* value, uint8_t* bufferSrc, int elementLength) -{ - value->value.visibleString.buf = (char*) malloc(elementLength + 1); - memcpy(value->value.visibleString.buf, bufferSrc, elementLength); - value->value.visibleString.buf[elementLength] = 0; - value->value.visibleString.size = elementLength; -} - -static int -parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) -{ - int bufPos = 0; - int elementLength = 0; - - int elementIndex = 0; - - int maxIndex = MmsValue_getArraySize(dataSetValues) - 1; - - while (bufPos < allDataLength) { - uint8_t tag = buffer[bufPos++]; - - if (elementIndex > maxIndex) { - if (DEBUG) printf("Malformed message: too much elements!\n"); - return 0; - } - - MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex); - - bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); - - if (bufPos + elementLength > allDataLength) { - if (DEBUG) printf("Malformed message: sub element is to large!\n"); - return 0; - } - - switch (tag) { - case 0x80: /* reserved for access result */ - printf(" found reserved value (tag 0x80)!\n"); - break; - case 0xa1: /* array */ - if (DEBUG) printf(" found array\n"); - if (MmsValue_getType(value) == MMS_ARRAY) { - if (!parseAllData(buffer + bufPos, elementLength, value)) - return -1; - } - break; - case 0xa2: /* structure */ - if (DEBUG) printf(" found structure\n"); - if (MmsValue_getType(value) == MMS_STRUCTURE) { - if (!parseAllData(buffer + bufPos, elementLength, value)) - return -1; - } - break; - case 0x83: /* boolean */ - if (DEBUG) printf(" found boolean\n"); - - if (MmsValue_getType(value) == MMS_BOOLEAN) { - MmsValue_setBoolean(value, BerDecoder_decodeBoolean(buffer, bufPos)); - } - else - if (DEBUG) printf(" message contains value of wrong type!\n"); - - break; - - case 0x84: /* BIT STRING */ - if (MmsValue_getType(value) == MMS_BIT_STRING) { - int padding = buffer[bufPos]; - int bitStringLength = (8 * (elementLength - 1)) - padding; - if (bitStringLength == value->value.bitString.size) { - memcpy(value->value.bitString.buf, buffer + bufPos + 1, - elementLength - 1); - } - else - printf("bit-string is of wrong size"); - } - break; - case 0x85: /* integer */ - if (MmsValue_getType(value) == MMS_INTEGER) { - if (elementLength <= value->value.integer->maxSize) { - value->value.integer->size = elementLength; - memcpy(value->value.integer->octets, buffer + bufPos, elementLength); - } - } - break; - case 0x86: /* unsigned integer */ - if (MmsValue_getType(value) == MMS_UNSIGNED) { - if (elementLength <= value->value.integer->maxSize) { - value->value.integer->size = elementLength; - memcpy(value->value.integer->octets, buffer + bufPos, elementLength); - } - } - break; - case 0x87: /* Float */ - if (MmsValue_getType(value) == MMS_FLOAT) { - if (elementLength == 9) { - MmsValue_setDouble(value, BerDecoder_decodeDouble(buffer, bufPos)); - } - else if (elementLength == 5) { - MmsValue_setFloat(value, BerDecoder_decodeFloat(buffer, bufPos)); - } - } - break; - - case 0x89: /* octet string */ - if (MmsValue_getType(value) == MMS_OCTET_STRING) { - if (elementLength <= value->value.octetString.maxSize) { - value->value.octetString.size = elementLength; - memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); - } - } - break; - case 0x8a: /* visible string */ - if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { - - if (value->value.visibleString.buf != NULL) { - if ((int32_t) value->value.visibleString.size >= elementLength) { - memcpy(value->value.visibleString.buf, buffer + bufPos, elementLength); - value->value.visibleString.buf[elementLength] = 0; - } - else { - free(value->value.visibleString.buf); - - createNewStringFromBufferElement(value, buffer + bufPos, elementLength); - } - } - else - createNewStringFromBufferElement(value, buffer + bufPos, elementLength); - - } - break; - case 0x8c: /* binary time */ - if (MmsValue_getType(value) == MMS_BINARY_TIME) { - if ((elementLength == 4) || (elementLength == 6)) { - memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); - } - } - break; - case 0x91: /* Utctime */ - if (elementLength == 8) { - if (MmsValue_getType(value) == MMS_UTC_TIME) { - MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); - } - else - if (DEBUG) printf(" message contains value of wrong type!\n"); - } - else - if (DEBUG) printf(" UTCTime element is of wrong size!\n"); - break; - default: - printf(" found unkown tag %02x\n", tag); - break; - } - - bufPos += elementLength; - - elementIndex++; - } - - return 1; -} - -static MmsValue* -parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure) -{ - int bufPos = 0; - int elementLength = 0; - - int elementIndex = 0; - - MmsValue* dataSetValues = NULL; - - while (bufPos < allDataLength) { - uint8_t tag = buffer[bufPos++]; - - bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); - - if (bufPos + elementLength > allDataLength) { - if (DEBUG) printf("Malformed message: sub element is to large!\n"); - goto exit_with_error; - } - - switch (tag) { - case 0x80: /* reserved for access result */ - break; - case 0xa1: /* array */ - break; - case 0xa2: /* structure */ - break; - case 0x83: /* boolean */ - break; - case 0x84: /* BIT STRING */ - break; - case 0x85: /* integer */ - break; - case 0x86: /* unsigned integer */ - break; - case 0x87: /* Float */ - break; - case 0x89: /* octet string */ - break; - case 0x8a: /* visible string */ - break; - case 0x8c: /* binary time */ - break; - case 0x91: /* Utctime */ - break; - default: - printf(" found unkown tag %02x\n", tag); - goto exit_with_error; - } - - bufPos += elementLength; - - elementIndex++; - } - - if (isStructure) - dataSetValues = MmsValue_createEmptyStructure(elementIndex); - else - dataSetValues = MmsValue_createEmtpyArray(elementIndex); - - elementIndex = 0; - bufPos = 0; - - while (bufPos < allDataLength) { - uint8_t tag = buffer[bufPos++]; - - bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); - - if (bufPos + elementLength > allDataLength) { - if (DEBUG) printf("Malformed message: sub element is too large!\n"); - goto exit_with_error; - } - - MmsValue* value = NULL; - - switch (tag) { - case 0xa1: /* array */ - if (DEBUG) printf(" found array\n"); - - value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false); - - if (value == NULL) - goto exit_with_error; - - break; - case 0xa2: /* structure */ - if (DEBUG) printf(" found structure\n"); - - value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true); - - if (value == NULL) - goto exit_with_error; - - break; - case 0x83: /* boolean */ - if (DEBUG) printf(" found boolean\n"); - value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos)); - - break; - - case 0x84: /* BIT STRING */ - { - int padding = buffer[bufPos]; - int bitStringLength = (8 * (elementLength - 1)) - padding; - value = MmsValue_newBitString(bitStringLength); - memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); - - } - break; - case 0x85: /* integer */ - value = MmsValue_newInteger(elementLength * 8); - memcpy(value->value.integer->octets, buffer + bufPos, elementLength); - break; - case 0x86: /* unsigned integer */ - value = MmsValue_newUnsigned(elementLength * 8); - memcpy(value->value.integer->octets, buffer + bufPos, elementLength); - break; - case 0x87: /* Float */ - if (elementLength == 9) - value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos)); - else if (elementLength == 5) - value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos)); - break; - - case 0x89: /* octet string */ - value = MmsValue_newOctetString(elementLength, elementLength); - memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); - break; - case 0x8a: /* visible string */ - value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength); - break; - case 0x8c: /* binary time */ - if (elementLength == 4) - value = MmsValue_newBinaryTime(true); - else if (elementLength == 6) - value = MmsValue_newBinaryTime(false); - - if ((elementLength == 4) || (elementLength == 6)) - memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); - - break; - case 0x91: /* Utctime */ - if (elementLength == 8) { - value = MmsValue_newUtcTime(0); - MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); - } - else - if (DEBUG) printf(" UTCTime element is of wrong size!\n"); - break; - default: - if (DEBUG) printf(" found unkown tag %02x\n", tag); - goto exit_with_error; - } - - bufPos += elementLength; - - if (value != NULL) { - MmsValue_setElement(dataSetValues, elementIndex, value); - elementIndex++; - } - } - - self->dataSetValuesSelfAllocated = true; - - return dataSetValues; - -exit_with_error: - - if (dataSetValues != NULL) - MmsValue_delete(dataSetValues); - - return NULL; -} - - -static int -parseGoosePayload(uint8_t* buffer, int apduLength, GooseSubscriber self) -{ - int bufPos = 0; - uint32_t timeAllowedToLive = 0; - uint32_t stNum = 0; - uint32_t sqNum = 0; - uint32_t confRev; - bool simulation = false; - bool ndsCom = false; - bool isMatching = false; - - uint32_t numberOfDatSetEntries = 0; - - if (buffer[bufPos++] == 0x61) { - int gooseLength; - bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); - - int gooseEnd = bufPos + gooseLength; - - while (bufPos < gooseEnd) { - int elementLength; - - uint8_t tag = buffer[bufPos++]; - bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); - - if (bufPos + elementLength > apduLength) { - if (DEBUG) printf("Malformed message: sub element is to large!\n"); - goto exit_with_fault; - } - - if (bufPos == -1) - goto exit_with_fault; - - switch(tag) { - case 0x80: /* gocbRef */ - if (DEBUG) printf(" Found gocbRef\n"); - - if (self->goCBRefLen == elementLength) { - if (memcmp(self->goCBRef, buffer + bufPos, elementLength) == 0) { - if (DEBUG) printf(" gocbRef is matching!\n"); - isMatching = true; - } - else return 0; - } - else - return 0; - - break; - - case 0x81: /* timeAllowedToLive */ - - timeAllowedToLive = BerDecoder_decodeUint32(buffer, elementLength, bufPos); - - if (DEBUG) printf(" Found timeAllowedToLive %u\n", timeAllowedToLive); - - break; - - case 0x82: - if (DEBUG) printf(" Found dataSet\n"); - break; - - case 0x83: - if (DEBUG) printf(" Found goId\n"); - break; - - case 0x84: - MmsValue_setUtcTimeByBuffer(self->timestamp, buffer + bufPos); - if (DEBUG) printf(" Found timestamp t: %" PRIu64 "\n", MmsValue_getUtcTimeInMs(self->timestamp)); - break; - - case 0x85: - stNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); - if (DEBUG) printf(" Found stNum: %u\n", stNum); - break; - - case 0x86: - sqNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); - if (DEBUG) printf(" Found sqNum: %u\n", sqNum); - break; - - case 0x87: - simulation = BerDecoder_decodeBoolean(buffer, bufPos); - if (DEBUG) printf(" Found simulation: %i\n", simulation); - break; - - case 0x88: - confRev = BerDecoder_decodeUint32(buffer, elementLength, bufPos); - if (DEBUG) printf(" Found confRev: %u\n", confRev); - break; - - case 0x89: - ndsCom = BerDecoder_decodeBoolean(buffer, bufPos); - if (DEBUG) printf(" Found ndsCom: %i\n", ndsCom); - break; - - case 0x8a: - numberOfDatSetEntries = BerDecoder_decodeUint32(buffer, elementLength, bufPos); - if (DEBUG) printf(" Found number of entries: %u\n", numberOfDatSetEntries); - break; - - case 0xab: - if (DEBUG) printf(" Found all data with length: %i\n", elementLength); - - if (self->dataSetValues == NULL) - self->dataSetValues = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false); - else - parseAllData(buffer + bufPos, elementLength, self->dataSetValues); - break; - - default: - if (DEBUG) printf(" Unknown tag %02x\n", tag); - break; - } - - bufPos += elementLength; - } - - if (isMatching) { - self->stNum = stNum; - self->sqNum = sqNum; - self->timeAllowedToLive = timeAllowedToLive; - self->confRev = confRev; - self->ndsCom = ndsCom; - self->simulation = simulation; - - return 1; - } - - return 0; - } - -exit_with_fault: - if (DEBUG) printf("Invalid goose payload\n"); - return -1; -} - -static int -parseGooseMessage(uint8_t* buffer, int numbytes, GooseSubscriber subscriber) -{ - int bufPos; - - if (numbytes < 22) return -1; - - /* skip ethernet addresses */ - bufPos = 12; - int headerLength = 14; - - /* check for VLAN tag */ - if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) { - bufPos += 4; /* skip VLAN tag */ - headerLength += 4; - } - - /* check for GOOSE Ethertype */ - if (buffer[bufPos++] != 0x88) - return -1; - if (buffer[bufPos++] != 0xb8) - return -1; - - uint16_t appId; - - appId = buffer[bufPos++] * 0x100; - appId += buffer[bufPos++]; - - uint16_t length; - - length = buffer[bufPos++] * 0x100; - length += buffer[bufPos++]; - - /* skip reserved fields */ - bufPos += 4; - - int apduLength = length - 8; - - if (numbytes != length + headerLength) { - if (DEBUG) - printf("Invalid PDU size\n"); - return -1; - } - - if (DEBUG) { - printf("GOOSE message:\n----------------\n"); - printf(" APPID: %u\n", appId); - printf(" LENGTH: %u\n", length); - printf(" APDU length: %i\n", apduLength); - } - - if (subscriber->appId >= 0) { - if (appId != (uint16_t) subscriber->appId) { - if (DEBUG) - printf("GOOSE message ignored due to wrong APPID value\n"); - - return 0; - } - } - - return parseGoosePayload(buffer + bufPos, apduLength, subscriber); -} - -static void -gooseSubscriberLoop(void* threadParameter) -{ - GooseSubscriber self = (GooseSubscriber) threadParameter; - - uint8_t* buffer = (uint8_t*) malloc(ETH_BUFFER_LENGTH); - - EthernetSocket socket; - - if (self->interfaceId == NULL) - socket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); - else - socket = Ethernet_createSocket(self->interfaceId, NULL); - - Ethernet_setProtocolFilter(socket, ETH_P_GOOSE); - - int running = 1; - - while (running) { - - int packetSize = Ethernet_receivePacket(socket, buffer, ETH_BUFFER_LENGTH); - - if (packetSize > 0) { - if (parseGooseMessage(buffer, packetSize, self) == 1) { - if (self->listener != NULL) { - self->listener(self, self->listenerParameter); - } - } - } - - Thread_sleep(1); - - running = self->running; - } - - free(buffer); - - Ethernet_destroySocket(socket); -} +#include "goose_receiver_internal.h" GooseSubscriber GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues) { - GooseSubscriber self = (GooseSubscriber) calloc(1, sizeof(struct sGooseSubscriber)); + GooseSubscriber self = (GooseSubscriber) GLOBAL_CALLOC(1, sizeof(struct sGooseSubscriber)); self->goCBRef = copyString(goCbRef); self->goCBRefLen = strlen(goCbRef); @@ -650,59 +48,40 @@ GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues) if (dataSetValues != NULL) self->dataSetValuesSelfAllocated = false; - self->running = false; - self->appId = -1; return self; } -void -GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId) +bool +GooseSubscriber_isValid(GooseSubscriber self) { - self->appId = (int32_t) appId; -} + if (self->stateValid == false) + return false; -void -GooseSubscriber_setInterfaceId(GooseSubscriber self, char* interfaceId) -{ - self->interfaceId = copyString(interfaceId); -} + if (Hal_getTimeInMs() > self->invalidityTime) + return false; -void -GooseSubscriber_subscribe(GooseSubscriber self) -{ - Thread thread = Thread_create((ThreadExecutionFunction) gooseSubscriberLoop, self, false); - self->receiver = thread; - self->running = true; - Thread_start(thread); + return true; } void -GooseSubscriber_unsubscribe(GooseSubscriber self) +GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId) { - if (self->running) { - self->running = false; - Thread_destroy(self->receiver); - } + self->appId = (int32_t) appId; } void GooseSubscriber_destroy(GooseSubscriber self) { - GooseSubscriber_unsubscribe(self); - - free(self->goCBRef); + GLOBAL_FREEMEM(self->goCBRef); MmsValue_delete(self->timestamp); if (self->dataSetValuesSelfAllocated) MmsValue_delete(self->dataSetValues); - if (self->interfaceId != NULL) - free(self->interfaceId); - - free(self); + GLOBAL_FREEMEM(self); } void diff --git a/src/goose/goose_subscriber.h b/src/goose/goose_subscriber.h index ade78e48..f9f09742 100644 --- a/src/goose/goose_subscriber.h +++ b/src/goose/goose_subscriber.h @@ -1,7 +1,7 @@ /* * goose_subscriber.h * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -70,6 +70,9 @@ typedef void (*GooseListener)(GooseSubscriber subscriber, void* parameter); GooseSubscriber GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues); +//char* +//GooseSubscriber_getGoCbRef(GooseSubscriber self); + /** * \brief set the APPID used by the subscriber to filter relevant messages. * @@ -82,30 +85,23 @@ void GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId); /** - * \brief set the ethernet interface that should be used. + * \brief Check if subscriber state is valid * - * \param self GooseSubscriber instance to operate on. - * \param interfaceId the id of the interface (e.g. a network device name like eth0 - * for linux or a numerical index for windows) - */ -void -GooseSubscriber_setInterfaceId(GooseSubscriber self, char* interfaceId); - -/** - * \brief Start listening to GOOSE messages + * A GOOSE subscriber is valid if TimeAllowedToLive timeout is not elapsed and GOOSE + * message were received with correct state and sequence ID. * - * \param self GooseSubscriber instance to operate on. */ -void -GooseSubscriber_subscribe(GooseSubscriber self); +bool +GooseSubscriber_isValid(GooseSubscriber self); + +//uint16_t +//GooseSubscriber_getAppId(GooseSubscriber self); -/** - * \brief Stop listening to GOOSE messages - * - * \param self GooseSubscriber instance to operate on. - */ void -GooseSubscriber_unsubscribe(GooseSubscriber self); +GooseSubscriber_setGoId(GooseSubscriber self, const char* goId); + +//char* +//GooseSubscriber_getGoId(GooseSubscriber self); void GooseSubscriber_destroy(GooseSubscriber self); @@ -138,6 +134,17 @@ GooseSubscriber_getTimeAllowedToLive(GooseSubscriber self); uint64_t GooseSubscriber_getTimestamp(GooseSubscriber self); +/** + * \brief get the data set values received with the last report + * + * Note: To prevent data corruption. The MmsValue instance received should + * only be used inside of the callback function, when the GOOSE receiver is + * running in a separate thread. + * + * \param self GooseSubscriber instance to operate on. + * + * \return MmsValue instance of the report data set + */ MmsValue* GooseSubscriber_getDataSetValues(GooseSubscriber self); diff --git a/src/hal/ethernet/bsd/ethernet_bsd.c b/src/hal/ethernet/bsd/ethernet_bsd.c index b9c8fe3c..b1eaf296 100644 --- a/src/hal/ethernet/bsd/ethernet_bsd.c +++ b/src/hal/ethernet/bsd/ethernet_bsd.c @@ -36,7 +36,8 @@ #include #include -#include "ethernet.h" +#include "libiec61850_platform_includes.h" +#include "hal_ethernet.h" struct sEthernetSocket { int bpf; // BPF device handle. @@ -181,7 +182,7 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) */ }; - EthernetSocket self = calloc(1, sizeof(struct sEthernetSocket)); + EthernetSocket self = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket)); if (!self) { printf("Could not allocate socket descriptor!\n"); @@ -189,7 +190,7 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) } // Copy default BPF filter program into descriptor. - self->bpfProgram.bf_insns = calloc(1, sizeof(destAddrFiltCode)); + self->bpfProgram.bf_insns = GLOBAL_CALLOC(1, sizeof(destAddrFiltCode)); if (!self->bpfProgram.bf_insns) { printf("Could not allocate memory for BPF filter program!\n"); @@ -212,8 +213,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) if (self->bpf == -1) { printf("Error opening BPF file handle!\n"); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); return NULL; } @@ -223,8 +224,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) if (fcntl(self->bpf, F_SETFL, &optval) == -1) { printf("Unable to change to non-blocking mode!\n"); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); return NULL; } @@ -233,8 +234,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) if (ioctl(self->bpf, BIOCSETIF, &ifr)) { printf("Unable to select interface %s!\n", interfaceId); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); return NULL; } @@ -242,8 +243,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) if (ioctl(self->bpf, BIOCIMMEDIATE, &self->bpfBufferSize) == -1) { printf("Unable to activate immediate mode!\n"); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); return NULL; } @@ -251,18 +252,18 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) if (ioctl(self->bpf, BIOCGBLEN, &self->bpfBufferSize) == -1) { printf("Unable to get BPF buffer lenght!\n"); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); return NULL; } // Allocate a buffer for the message reception. - self->bpfBuffer = calloc(1, self->bpfBufferSize); + self->bpfBuffer = GLOBAL_CALLOC(1, self->bpfBufferSize); if (!self->bpfBuffer) { printf("Unable to allocate BPF RX buffer!\n"); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); return NULL; } self->bpfPositon = self->bpfBuffer; @@ -273,9 +274,9 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) if (ioctl(self->bpf, BIOCPROMISC, &optval) == -1) { printf("Unable to activate promiscous mode!\n"); - free(self->bpfProgram.bf_insns); - free(self->bpfBuffer); - free(self); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self->bpfBuffer); + GLOBAL_FREEMEM(self); return NULL; } @@ -313,7 +314,7 @@ int Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) struct bpf_hdr *header = (struct bpf_hdr *)(self->bpfPositon); // Check if the target buffer is big enough to hold the received ethernet frame. - if (bufferSize >= header->bh_caplen) + if ((unsigned int) bufferSize >= header->bh_caplen) { // Copy the frame to the target buffer. memcpy(buffer, self->bpfPositon + header->bh_hdrlen, header->bh_caplen); @@ -346,7 +347,14 @@ void Ethernet_destroySocket(EthernetSocket self) close(self->bpf); // Free all dynamic resources used by the ethernet socket. - free(self->bpfBuffer); - free(self->bpfProgram.bf_insns); - free(self); + GLOBAL_FREEMEM(self->bpfBuffer); + GLOBAL_FREEMEM(self->bpfProgram.bf_insns); + GLOBAL_FREEMEM(self); } + +bool +Ethernet_isSupported() +{ + return true; +} + diff --git a/src/hal/ethernet/linux/ethernet_linux.c b/src/hal/ethernet/linux/ethernet_linux.c index f9dfadf5..82e65e95 100644 --- a/src/hal/ethernet/linux/ethernet_linux.c +++ b/src/hal/ethernet/linux/ethernet_linux.c @@ -35,7 +35,8 @@ #include #include -#include "ethernet.h" +#include "libiec61850_platform_includes.h" +#include "hal_ethernet.h" struct sEthernetSocket { int rawSocket; @@ -101,13 +102,13 @@ Ethernet_getInterfaceMACAddress(char* interfaceId, uint8_t* addr) EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) { - EthernetSocket ethernetSocket = calloc(1, sizeof(struct sEthernetSocket)); + EthernetSocket ethernetSocket = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket)); ethernetSocket->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (ethernetSocket->rawSocket == -1) { printf("Error creating raw socket!\n"); - free(ethernetSocket); + GLOBAL_FREEMEM(ethernetSocket); return NULL; } @@ -163,6 +164,12 @@ void Ethernet_destroySocket(EthernetSocket ethSocket) { close(ethSocket->rawSocket); - free(ethSocket); + GLOBAL_FREEMEM(ethSocket); +} + +bool +Ethernet_isSupported() +{ + return true; } diff --git a/src/hal/ethernet/win32/ethernet_win32.c b/src/hal/ethernet/win32/ethernet_win32.c index 05eb67f1..7095382a 100644 --- a/src/hal/ethernet/win32/ethernet_win32.c +++ b/src/hal/ethernet/win32/ethernet_win32.c @@ -23,12 +23,16 @@ #include "stack_config.h" -#if CONFIG_INCLUDE_ETHERNET_WINDOWS == 1 - #include #include #include #include + +#include "hal_ethernet.h" + +#if (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1) + + #include #include @@ -38,8 +42,6 @@ #pragma comment (lib, "IPHLPAPI.lib") #endif -#include "ethernet.h" - #define HAVE_REMOTE #include "pcap.h" @@ -89,7 +91,7 @@ static pgetadaptersaddresses GetAdaptersAddresses; static bool dllLoaded = false; static void -loadDLLs() +loadDLLs(void) { HINSTANCE hDll = LoadLibrary("iphlpapi.dll"); @@ -103,7 +105,7 @@ loadDLLs() "GetAdaptersAddresses"); if (GetAdaptersAddresses == NULL) - printf("Error loading GetAdaptersAddresses from iphlpapi.dll (%d)\n", GetLastError()); + printf("Error loading GetAdaptersAddresses from iphlpapi.dll (%d)\n", (int) GetLastError()); } #endif /* __MINGW64_VERSION_MAJOR */ @@ -155,7 +157,7 @@ getInterfaceName(int interfaceIndex) return interfaceName; } -void +static void getAdapterMacAddress(char* pcapAdapterName, uint8_t* macAddress) { PIP_ADAPTER_ADDRESSES pAddresses = NULL; @@ -224,7 +226,7 @@ Ethernet_getInterfaceMACAddress(char* interfaceId, uint8_t* addr) long interfaceIndex = strtol(interfaceId, &endPtr, 10); - if (*endPtr != NULL) { + if (endPtr != NULL) { printf("Ethernet_getInterfaceMACAddress: invalid interface number %s\n", interfaceId); return; } @@ -315,4 +317,50 @@ Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) } } -#endif +bool +Ethernet_isSupported() +{ + return true; +} + +#else + +bool +Ethernet_isSupported() +{ + return false; +} + +void +Ethernet_getInterfaceMACAddress(char* interfaceId, uint8_t* addr) +{ +} + +EthernetSocket +Ethernet_createSocket(char* interfaceId, uint8_t* destAddress) +{ + return NULL; +} + +void +Ethernet_destroySocket(EthernetSocket ethSocket) +{ +} + +void +Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize) +{ +} + +void +Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType) +{ +} + +int +Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) +{ + return 0; +} + +#endif /* (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1) */ diff --git a/src/hal/filesystem/linux/file_provider_linux.c b/src/hal/filesystem/linux/file_provider_linux.c index a5a88f45..91bf3d3e 100644 --- a/src/hal/filesystem/linux/file_provider_linux.c +++ b/src/hal/filesystem/linux/file_provider_linux.c @@ -32,7 +32,9 @@ #include #include -#include "filesystem.h" +#include "libiec61850_platform_includes.h" + +#include "hal_filesystem.h" #include "stack_config.h" @@ -154,7 +156,7 @@ FileSystem_openDirectory(char* directoryName) DirectoryHandle handle = NULL; if (dirHandle != NULL) { - handle = malloc(sizeof(struct sDirectoryHandle)); + handle = GLOBAL_MALLOC(sizeof(struct sDirectoryHandle)); handle->handle = dirHandle; } @@ -190,7 +192,7 @@ void FileSystem_closeDirectory(DirectoryHandle directory) { closedir(directory->handle); - free(directory); + GLOBAL_FREEMEM(directory); } #if 0 diff --git a/src/hal/filesystem/win32/file_provider_win32.c b/src/hal/filesystem/win32/file_provider_win32.c index c0b6a182..01250219 100644 --- a/src/hal/filesystem/win32/file_provider_win32.c +++ b/src/hal/filesystem/win32/file_provider_win32.c @@ -30,8 +30,9 @@ #include #include -#include "filesystem.h" +#include "hal_filesystem.h" +#include "libiec61850_platform_includes.h" #include "stack_config.h" #include @@ -131,7 +132,7 @@ FileSystem_openDirectory(char* directoryName) createFullPathFromFileName(fullPath, directoryName); - DirectoryHandle dirHandle = (DirectoryHandle) calloc(1, sizeof(struct sDirectoryHandle)); + DirectoryHandle dirHandle = (DirectoryHandle) GLOBAL_CALLOC(1, sizeof(struct sDirectoryHandle)); strcat(fullPath, "\\*"); @@ -141,7 +142,7 @@ FileSystem_openDirectory(char* directoryName) dirHandle->available = true; if (dirHandle->handle == INVALID_HANDLE_VALUE) { - free(dirHandle); + GLOBAL_FREEMEM(dirHandle); return NULL; } else @@ -226,27 +227,6 @@ void FileSystem_closeDirectory(DirectoryHandle directory) { FindClose(directory->handle); - free(directory); + GLOBAL_FREEMEM(directory); } -#if 0 -int -main(int argc, char** argv) -{ - DirectoryHandle directory = FileSystem_openDirectory("/"); - - if (directory != NULL) { - char* fileName = FileSystem_readDirectory(directory); - - - while (fileName != NULL) { - printf("FILE: (%s)\n", fileName); - fileName = FileSystem_readDirectory(directory); - } - - FileSystem_closeDirectory(directory); - } - else - printf("Error opening directory!\n"); -} -#endif diff --git a/src/hal/socket/bsd/socket_bsd.c b/src/hal/socket/bsd/socket_bsd.c index 770b0039..09457212 100644 --- a/src/hal/socket/bsd/socket_bsd.c +++ b/src/hal/socket/bsd/socket_bsd.c @@ -1,7 +1,7 @@ /* * socket_bsd.c * - * Copyright 2013 Michael Zillgith, contributed to the project by Michael Clausen (School of engineering Valais). + * Copyright 2013, 2014 Michael Zillgith, contributions by Michael Clausen (School of engineering Valais). * * This file is part of libIEC61850. * @@ -21,7 +21,7 @@ * See COPYING file for the complete license text. */ -#include "socket.h" +#include "hal_socket.h" #include #include #include @@ -38,7 +38,7 @@ #include // required for TCP keepalive -#include "thread.h" +#include "hal_thread.h" #include "libiec61850_platform_includes.h" @@ -48,6 +48,7 @@ struct sSocket { int fd; + uint32_t connectTimeout; }; struct sServerSocket { @@ -55,6 +56,58 @@ struct sServerSocket { int backLog; }; +struct sHandleSet { + fd_set handles; + int maxHandle; +}; + +HandleSet +Handleset_new(void) +{ + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = -1; + } + return result; +} + +void +Handleset_addSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != -1) { + FD_SET(sock->fd, &self->handles); + if (sock->fd > self->maxHandle) { + self->maxHandle = sock->fd; + } + } +} + +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs) +{ + int result; + + if (self != NULL && self->maxHandle >= 0) { + struct timeval timeout; + + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; + result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); + } else { + result = -1; + } + + return result; +} + +void +Handleset_destroy(HandleSet self) +{ + GLOBAL_FREEMEM(self); +} + static void activateKeepAlive(int sd) { @@ -79,7 +132,7 @@ activateKeepAlive(int sd) } static bool -prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr) +prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) { memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); @@ -101,17 +154,15 @@ prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr) return true; } -#if 0 static void setSocketNonBlocking(Socket self) { int flags = fcntl(self->fd, F_GETFL, 0); fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); } -#endif ServerSocket -TcpServerSocket_create(char* address, int port) +TcpServerSocket_create(const char* address, int port) { ServerSocket serverSocket = NULL; @@ -129,7 +180,7 @@ TcpServerSocket_create(char* address, int port) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int)); if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) { - serverSocket = malloc(sizeof(struct sServerSocket)); + serverSocket = GLOBAL_MALLOC(sizeof(struct sServerSocket)); serverSocket->fd = fd; serverSocket->backLog = 0; } @@ -141,6 +192,8 @@ TcpServerSocket_create(char* address, int port) #if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 activateKeepAlive(fd); #endif + + setSocketNonBlocking((Socket) serverSocket); } return serverSocket; @@ -201,21 +254,28 @@ ServerSocket_destroy(ServerSocket self) Thread_sleep(10); - free(self); + GLOBAL_FREEMEM(self); } Socket TcpSocket_create() { - Socket self = malloc(sizeof(struct sSocket)); + Socket self = GLOBAL_MALLOC(sizeof(struct sSocket)); self->fd = -1; return self; } -int -Socket_connect(Socket self, char* address, int port) +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + + +bool +Socket_connect(Socket self, const char* address, int port) { struct sockaddr_in serverAddress; @@ -223,7 +283,7 @@ Socket_connect(Socket self, char* address, int port) printf("Socket_connect: %s:%i\n", address, port); if (!prepareServerAddress(address, port, &serverAddress)) - return 0; + return false; self->fd = socket(AF_INET, SOCK_STREAM, 0); @@ -231,10 +291,25 @@ Socket_connect(Socket self, char* address, int port) activateKeepAlive(self->fd); #endif - if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) - return 0; + fd_set fdSet; + FD_ZERO(&fdSet); + FD_SET(self->fd, &fdSet); + + fcntl(self->fd, F_SETFL, O_NONBLOCK); + + if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { + if (errno != EINPROGRESS) + return false; + } + + struct timeval timeout; + timeout.tv_sec = self->connectTimeout / 1000; + timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + + if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) < 0) + return false; else - return 1; + return true; } char* @@ -265,7 +340,7 @@ Socket_getPeerAddress(Socket self) else return NULL ; - char* clientConnection = malloc(strlen(addrString) + 9); + char* clientConnection = GLOBAL_MALLOC(strlen(addrString) + 9); if (isIPv6) @@ -284,7 +359,10 @@ Socket_read(Socket self, uint8_t* buf, int size) if (self->fd == -1) return -1; - int read_bytes = read(self->fd, buf, size); + int read_bytes = recv(self->fd, buf, size, MSG_DONTWAIT); + + if (read_bytes == 0) + return -1; if (read_bytes == -1) { int error = errno; @@ -300,9 +378,8 @@ Socket_read(Socket self, uint8_t* buf, int size) return -1; } } - else { - return read_bytes; - } + + return read_bytes; } int @@ -326,5 +403,5 @@ Socket_destroy(Socket self) Thread_sleep(10); - free(self); + GLOBAL_FREEMEM(self); } diff --git a/src/hal/socket/linux/socket_linux.c b/src/hal/socket/linux/socket_linux.c index be6f838e..87c22a5b 100644 --- a/src/hal/socket/linux/socket_linux.c +++ b/src/hal/socket/linux/socket_linux.c @@ -1,7 +1,7 @@ /* * socket_linux.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -21,7 +21,7 @@ * See COPYING file for the complete license text. */ -#include "socket.h" +#include "hal_socket.h" #include #include #include @@ -38,7 +38,7 @@ #include // required for TCP keepalive -#include "thread.h" +#include "hal_thread.h" #include "libiec61850_platform_includes.h" @@ -48,6 +48,7 @@ struct sSocket { int fd; + uint32_t connectTimeout; }; struct sServerSocket { @@ -55,6 +56,58 @@ struct sServerSocket { int backLog; }; +struct sHandleSet { + fd_set handles; + int maxHandle; +}; + +HandleSet +Handleset_new(void) +{ + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = -1; + } + return result; +} + +void +Handleset_addSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != -1) { + FD_SET(sock->fd, &self->handles); + if (sock->fd > self->maxHandle) { + self->maxHandle = sock->fd; + } + } +} + +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs) +{ + int result; + + if (self != NULL && self->maxHandle >= 0) { + struct timeval timeout; + + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; + result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); + } else { + result = -1; + } + + return result; +} + +void +Handleset_destroy(HandleSet self) +{ + GLOBAL_FREEMEM(self); +} + static void activateKeepAlive(int sd) { @@ -80,7 +133,7 @@ activateKeepAlive(int sd) } static bool -prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr) +prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) { memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); @@ -102,17 +155,23 @@ prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr) return true; } -#if 0 static void setSocketNonBlocking(Socket self) { int flags = fcntl(self->fd, F_GETFL, 0); fcntl(self->fd, F_SETFL, flags | O_NONBLOCK); } -#endif + +static void +activateTcpNoDelay(Socket self) +{ + /* activate TCP_NODELAY option - packets will be sent immediately */ + int flag = 1; + setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); +} ServerSocket -TcpServerSocket_create(char* address, int port) +TcpServerSocket_create(const char* address, int port) { ServerSocket serverSocket = NULL; @@ -130,9 +189,11 @@ TcpServerSocket_create(char* address, int port) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int)); if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) { - serverSocket = malloc(sizeof(struct sServerSocket)); + serverSocket = GLOBAL_MALLOC(sizeof(struct sServerSocket)); serverSocket->fd = fd; serverSocket->backLog = 0; + + setSocketNonBlocking((Socket) serverSocket); } else { close(fd); @@ -153,6 +214,8 @@ ServerSocket_listen(ServerSocket self) listen(self->fd, self->backLog); } + +/* CHANGED TO MAKE NON-BLOCKING --> RETURNS NULL IF NO CONNECTION IS PENDING */ Socket ServerSocket_accept(ServerSocket self) { @@ -165,6 +228,8 @@ ServerSocket_accept(ServerSocket self) if (fd >= 0) { conSocket = TcpSocket_create(); conSocket->fd = fd; + + activateTcpNoDelay(conSocket); } return conSocket; @@ -202,21 +267,30 @@ ServerSocket_destroy(ServerSocket self) Thread_sleep(10); - free(self); + GLOBAL_FREEMEM(self); } Socket TcpSocket_create() { - Socket self = malloc(sizeof(struct sSocket)); + Socket self = GLOBAL_MALLOC(sizeof(struct sSocket)); self->fd = -1; + self->connectTimeout = 5000; return self; } -int -Socket_connect(Socket self, char* address, int port) + +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + + +bool +Socket_connect(Socket self, const char* address, int port) { struct sockaddr_in serverAddress; @@ -224,18 +298,36 @@ Socket_connect(Socket self, char* address, int port) printf("Socket_connect: %s:%i\n", address, port); if (!prepareServerAddress(address, port, &serverAddress)) - return 0; + return false; self->fd = socket(AF_INET, SOCK_STREAM, 0); + fd_set fdSet; + FD_ZERO(&fdSet); + FD_SET(self->fd, &fdSet); + + activateTcpNoDelay(self); + #if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1 activateKeepAlive(self->fd); #endif - if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) - return 0; + fcntl(self->fd, F_SETFL, O_NONBLOCK); + + if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { + if (errno != EINPROGRESS) + return false; + } + + struct timeval timeout; + timeout.tv_sec = self->connectTimeout / 1000; + timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + + if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) < 0) + return false; else - return 1; + return true; + } char* @@ -266,7 +358,7 @@ Socket_getPeerAddress(Socket self) else return NULL ; - char* clientConnection = malloc(strlen(addrString) + 9); + char* clientConnection = GLOBAL_MALLOC(strlen(addrString) + 9); if (isIPv6) @@ -285,7 +377,10 @@ Socket_read(Socket self, uint8_t* buf, int size) if (self->fd == -1) return -1; - int read_bytes = read(self->fd, buf, size); + int read_bytes = recv(self->fd, buf, size, MSG_DONTWAIT); + + if (read_bytes == 0) + return -1; if (read_bytes == -1) { int error = errno; @@ -301,9 +396,8 @@ Socket_read(Socket self, uint8_t* buf, int size) return -1; } } - else { - return read_bytes; - } + + return read_bytes; } int @@ -327,5 +421,5 @@ Socket_destroy(Socket self) Thread_sleep(10); - free(self); + GLOBAL_FREEMEM(self); } diff --git a/src/hal/socket/win32/socket_win32.c b/src/hal/socket/win32/socket_win32.c index 11430107..789de3b7 100644 --- a/src/hal/socket/win32/socket_win32.c +++ b/src/hal/socket/win32/socket_win32.c @@ -1,7 +1,7 @@ /* * socket_win32.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -29,7 +29,8 @@ #pragma comment (lib, "Ws2_32.lib") -#include "socket.h" +#include "libiec61850_platform_includes.h" +#include "hal_socket.h" #include "stack_config.h" @@ -45,6 +46,7 @@ struct tcp_keepalive { struct sSocket { SOCKET fd; + uint32_t connectTimeout; }; struct sServerSocket { @@ -52,6 +54,58 @@ struct sServerSocket { int backLog; }; +struct sHandleSet { + fd_set handles; + int maxHandle; +}; + +HandleSet +Handleset_new(void) +{ + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = -1; + } + return result; +} + +void +Handleset_addSocket(HandleSet self, const Socket sock) +{ + if (self != NULL && sock != NULL && sock->fd != -1) { + FD_SET(sock->fd, &self->handles); + if (sock->fd > self->maxHandle) { + self->maxHandle = sock->fd; + } + } +} + +int +Handleset_waitReady(HandleSet self, unsigned int timeoutMs) +{ + int result; + + if (self != NULL && self->maxHandle >= 0) { + struct timeval timeout; + + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; + result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout); + } else { + result = -1; + } + + return result; +} + +void +Handleset_destroy(HandleSet self) +{ + GLOBAL_FREEMEM(self); +} + static void activateKeepAlive(SOCKET s) { @@ -65,13 +119,30 @@ activateKeepAlive(SOCKET s) if (WSAIoctl(s, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &retVal, NULL, NULL) == SOCKET_ERROR) { - printf("WSAIotcl(SIO_KEEPALIVE_VALS) failed; %d\n", - WSAGetLastError()); + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: WSAIotcl(SIO_KEEPALIVE_VALS) failed: %d\n", + WSAGetLastError()); } } +static void +setSocketNonBlocking(Socket self) +{ + unsigned long mode = 1; + if (ioctlsocket(self->fd, FIONBIO, &mode) != 0) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: failed to set socket non-blocking!\n"); + } + + /* activate TCP_NODELAY */ + + int tcpNoDelay = 1; + + setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&tcpNoDelay, sizeof(int)); +} + static bool -prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr) +prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) { memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); @@ -94,7 +165,7 @@ prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr) } ServerSocket -TcpServerSocket_create(char* address, int port) +TcpServerSocket_create(const char* address, int port) { ServerSocket serverSocket = NULL; int ec; @@ -102,7 +173,8 @@ TcpServerSocket_create(char* address, int port) SOCKET listen_socket = INVALID_SOCKET; if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) { - printf("winsock error: code %i\n"); + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: winsock error: code %i\n", ec); return NULL; } @@ -118,7 +190,8 @@ TcpServerSocket_create(char* address, int port) #endif if (listen_socket == INVALID_SOCKET) { - printf("socket failed with error: %i\n", WSAGetLastError()); + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: socket failed with error: %i\n", WSAGetLastError()); WSACleanup(); return NULL; } @@ -129,17 +202,20 @@ TcpServerSocket_create(char* address, int port) ec = bind(listen_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (ec == SOCKET_ERROR) { - printf("bind failed with error:%i\n", WSAGetLastError()); + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: bind failed with error:%i\n", WSAGetLastError()); closesocket(listen_socket); WSACleanup(); return NULL; } - serverSocket = (ServerSocket) malloc(sizeof(struct sServerSocket)); + serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket)); serverSocket->fd = listen_socket; serverSocket->backLog = 10; + setSocketNonBlocking((Socket) serverSocket); + return serverSocket; } @@ -161,6 +237,8 @@ ServerSocket_accept(ServerSocket self) if (fd >= 0) { conSocket = TcpSocket_create(); conSocket->fd = fd; + + setSocketNonBlocking(conSocket); } return conSocket; @@ -183,27 +261,34 @@ ServerSocket_destroy(ServerSocket self) Socket TcpSocket_create() { - Socket self = (Socket) malloc(sizeof(struct sSocket)); + Socket self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket)); - self->fd = -1; + self->fd = INVALID_SOCKET; return self; } -int -Socket_connect(Socket self, char* address, int port) +void +Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + +bool +Socket_connect(Socket self, const char* address, int port) { - struct hostent *server; struct sockaddr_in serverAddress; WSADATA wsa; + int ec; - if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { - printf("winsock error: code %i\n"); - return 0; + if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) { + if (DEBUG_SOCKET) + printf("WIN32_SOCKET: winsock error: code %i\n", ec); + return false; } if (!prepareServerAddress(address, port, &serverAddress)) - return 0; + return false; self->fd = socket(AF_INET, SOCK_STREAM, 0); @@ -211,12 +296,35 @@ Socket_connect(Socket self, char* address, int port) activateKeepAlive(self->fd); #endif - if (connect(self->fd, (struct sockaddr *) &serverAddress,sizeof(serverAddress)) < 0) { - printf("Socket failed connecting!\n"); - return 0; - } - else - return 1; + setSocketNonBlocking(self); + + fd_set fdSet; + FD_ZERO(&fdSet); + FD_SET(self->fd, &fdSet); + +// if (connect(self->fd, (struct sockaddr *) &serverAddress,sizeof(serverAddress)) < 0) { +// if (DEBUG_SOCKET) +// printf("WIN32_SOCKET: Socket failed connecting!\n"); +// return false; +// } +// else { +// +// return true; +// } + + if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return false; + } + + struct timeval timeout; + timeout.tv_sec = self->connectTimeout / 1000; + timeout.tv_usec = (self->connectTimeout % 1000) * 1000; + + if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) == SOCKET_ERROR) + return false; + else + return true; } char* @@ -252,7 +360,7 @@ Socket_getPeerAddress(Socket self) else return NULL; - char* clientConnection = (char*) malloc(strlen(addrString) + 9); + char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9); if (isIPv6) sprintf(clientConnection, "[%s]:%i", addrString, port); @@ -265,7 +373,19 @@ Socket_getPeerAddress(Socket self) int Socket_read(Socket self, uint8_t* buf, int size) { - return recv(self->fd, (char*) buf, size, 0); + int bytes_read = recv(self->fd, (char*) buf, size, 0); + + if (bytes_read == 0) // peer has closed socket + return -1; + + if (bytes_read == SOCKET_ERROR) { + if (WSAGetLastError() == WSAEWOULDBLOCK) + return 0; + else + return -1; + } + + return bytes_read; } int @@ -277,7 +397,7 @@ Socket_write(Socket self, uint8_t* buf, int size) void Socket_destroy(Socket self) { - if (self->fd != -1) { + if (self->fd != INVALID_SOCKET) { closesocket(self->fd); } diff --git a/src/hal/thread/linux/thread_linux.c b/src/hal/thread/linux/thread_linux.c index a2b13343..cf8ec73e 100644 --- a/src/hal/thread/linux/thread_linux.c +++ b/src/hal/thread/linux/thread_linux.c @@ -26,7 +26,9 @@ #include #include #include -#include "thread.h" +#include "hal_thread.h" + +#include "libiec61850_platform_includes.h" struct sThread { ThreadExecutionFunction function; @@ -39,7 +41,7 @@ struct sThread { Semaphore Semaphore_create(int initialValue) { - Semaphore self = malloc(sizeof(sem_t)); + Semaphore self = GLOBAL_MALLOC(sizeof(sem_t)); sem_init((sem_t*) self, 0, initialValue); @@ -63,18 +65,20 @@ void Semaphore_destroy(Semaphore self) { sem_destroy((sem_t*) self); - free(self); + GLOBAL_FREEMEM(self); } Thread Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy) { - Thread thread = malloc(sizeof(struct sThread)); + Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread)); - thread->parameter = parameter; - thread->function = function; - thread->state = 0; - thread->autodestroy = autodestroy; + if (thread != NULL) { + thread->parameter = parameter; + thread->function = function; + thread->state = 0; + thread->autodestroy = autodestroy; + } return thread; } @@ -86,9 +90,9 @@ destroyAutomaticThread(void* parameter) thread->function(thread->parameter); - free(thread); + GLOBAL_FREEMEM(thread); - return NULL; + pthread_exit(NULL); } void @@ -111,7 +115,7 @@ Thread_destroy(Thread thread) pthread_join(thread->pthread, NULL); } - free(thread); + GLOBAL_FREEMEM(thread); } void diff --git a/src/hal/thread/win32/thread_win32.c b/src/hal/thread/win32/thread_win32.c index 81018585..02498ff1 100644 --- a/src/hal/thread/win32/thread_win32.c +++ b/src/hal/thread/win32/thread_win32.c @@ -23,7 +23,8 @@ #include #include -#include "thread.h" +#include "libiec61850_platform_includes.h" +#include "hal_thread.h" struct sThread { ThreadExecutionFunction function; @@ -59,7 +60,7 @@ Thread Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy) { DWORD threadId; - Thread thread = (Thread) malloc(sizeof(struct sThread)); + Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread)); thread->parameter = parameter; thread->function = function; @@ -89,7 +90,7 @@ Thread_destroy(Thread thread) CloseHandle(thread->handle); - free(thread); + GLOBAL_FREEMEM(thread); } void diff --git a/src/mms/asn1/asn1_ber_primitive_value.c b/src/mms/asn1/asn1_ber_primitive_value.c index 4d4d7e5a..d08e885b 100644 --- a/src/mms/asn1/asn1_ber_primitive_value.c +++ b/src/mms/asn1/asn1_ber_primitive_value.c @@ -28,11 +28,11 @@ Asn1PrimitiveValue* Asn1PrimitiveValue_create(int size) { - Asn1PrimitiveValue* self = (Asn1PrimitiveValue*) malloc(sizeof(Asn1PrimitiveValue)); + Asn1PrimitiveValue* self = (Asn1PrimitiveValue*) GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue)); self->size = size; self->maxSize = size; - self->octets = (uint8_t*) calloc(1, size); + self->octets = (uint8_t*) GLOBAL_CALLOC(1, size); return self; } @@ -40,22 +40,22 @@ Asn1PrimitiveValue_create(int size) //Asn1PrimitiveValue* //Asn1PrimitiveValue_createFromBuffer(uint8_t buffer, int bufferSize) //{ -// Asn1PrimitiveValue* self = malloc(sizeof(Asn1PrimitiveValue)); +// Asn1PrimitiveValue* self = GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue)); // self->size = bufferSize; // self->maxSize = bufferSize; -// self->octets = malloc(1, bufferSize); +// self->octets = GLOBAL_MALLOC(1, bufferSize); // //} Asn1PrimitiveValue* Asn1PrimitiveValue_clone(Asn1PrimitiveValue* self) { - Asn1PrimitiveValue* clone = (Asn1PrimitiveValue*) malloc(sizeof(Asn1PrimitiveValue)); + Asn1PrimitiveValue* clone = (Asn1PrimitiveValue*) GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue)); clone->size = self->size; clone->maxSize = self->maxSize; - clone->octets = (uint8_t*) malloc(self->maxSize); + clone->octets = (uint8_t*) GLOBAL_MALLOC(self->maxSize); memcpy(clone->octets, self->octets, clone->maxSize); @@ -90,6 +90,6 @@ Asn1PrimitiveValue_getMaxSize(Asn1PrimitiveValue* self) void Asn1PrimitiveValue_destroy(Asn1PrimitiveValue* self) { - free(self->octets); - free(self); + GLOBAL_FREEMEM(self->octets); + GLOBAL_FREEMEM(self); } diff --git a/src/mms/asn1/ber_decode.c b/src/mms/asn1/ber_decode.c index 18f2fa52..bbd2231f 100644 --- a/src/mms/asn1/ber_decode.c +++ b/src/mms/asn1/ber_decode.c @@ -62,7 +62,7 @@ BerDecoder_decodeLength(uint8_t* buffer, int* length, int bufPos, int maxBufPos) char* BerDecoder_decodeString(uint8_t* buffer, int strlen, int bufPos, int maxBufPos) { - char* string = (char*) malloc(strlen + 1); + char* string = (char*) GLOBAL_MALLOC(strlen + 1); memcpy(string, buffer + bufPos, strlen); string[strlen] = 0; diff --git a/src/mms/asn1/ber_encoder.c b/src/mms/asn1/ber_encoder.c index c0bf2aef..f22f9e2b 100644 --- a/src/mms/asn1/ber_encoder.c +++ b/src/mms/asn1/ber_encoder.c @@ -70,7 +70,7 @@ BerEncoder_encodeBoolean(uint8_t tag, bool value, uint8_t* buffer, int bufPos) } int -BerEncoder_encodeStringWithTag(uint8_t tag, char* string, uint8_t* buffer, int bufPos) +BerEncoder_encodeStringWithTag(uint8_t tag, const char* string, uint8_t* buffer, int bufPos) { buffer[bufPos++] = tag; @@ -341,7 +341,7 @@ BerEncoder_determineLengthSize(uint32_t length) } int -BerEncoder_determineEncodedStringSize(char* string) +BerEncoder_determineEncodedStringSize(const char* string) { if (string != NULL) { int size = 1; @@ -359,13 +359,13 @@ BerEncoder_determineEncodedStringSize(char* string) } int -BerEncoder_encodeOIDToBuffer(char* oidString, uint8_t* buffer, int maxBufLen) +BerEncoder_encodeOIDToBuffer(const char* oidString, uint8_t* buffer, int maxBufLen) { int encodedBytes = 0; int x = atoi(oidString); - char* separator = strchr(oidString, '.'); + const char* separator = strchr(oidString, '.'); if (separator == NULL) return 0; diff --git a/src/mms/iso_client/iso_client_connection.c b/src/mms/iso_client/iso_client_connection.c new file mode 100644 index 00000000..b279f08f --- /dev/null +++ b/src/mms/iso_client/iso_client_connection.c @@ -0,0 +1,589 @@ +/* + * iso_client_connection.c + * + * Client side representation of the ISO stack (COTP, session, presentation, ACSE) + * + * Copyright 2013 Michael Zillgith + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +#include "libiec61850_platform_includes.h" + +#include "stack_config.h" + +#include "hal_socket.h" +#include "hal_thread.h" +#include "cotp.h" +#include "iso_session.h" +#include "iso_presentation.h" +#include "iso_client_connection.h" +#include "acse.h" + +#ifndef DEBUG_ISO_CLIENT +#ifdef DEBUG +#define DEBUG_ISO_CLIENT 1 +#else +#define DEBUG_ISO_CLIENT 0 +#endif /*DEBUG */ +#endif /* DEBUG_ISO_SERVER */ + +#define STATE_IDLE 0 +#define STATE_ASSOCIATED 1 +#define STATE_ERROR 2 + +#define TPKT_RFC1006_HEADER_SIZE 4 + +#define ISO_CLIENT_BUFFER_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100 + +struct sIsoClientConnection +{ + IsoIndicationCallback callback; + void* callbackParameter; + volatile int state; + Socket socket; + CotpConnection* cotpConnection; + IsoPresentation* presentation; + IsoSession* session; + AcseConnection acseConnection; + + uint8_t* sendBuffer; /* ISO/MMS send buffer */ + uint8_t* receiveBuf; /* ISO/MMS receive buffer */ + ByteBuffer* receiveBuffer; + + ByteBuffer* transmitPayloadBuffer; + Semaphore transmitBufferMutex; + + ByteBuffer* receivePayloadBuffer; + Semaphore receiveBufferMutex; + + uint8_t* cotpReadBuf; + uint8_t* cotpWriteBuf; + + ByteBuffer* cotpReadBuffer; + ByteBuffer* cotpWriteBuffer; + + volatile bool handlingThreadRunning; + volatile bool stopHandlingThread; + volatile bool destroyHandlingThread; + volatile bool startHandlingThread; + + Thread thread; +}; + +static void +connectionHandlingThread(IsoClientConnection self) +{ + IsoSessionIndication sessionIndication; + + self->handlingThreadRunning = true; + self->stopHandlingThread = false; + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: new connection %p\n", self); + + /* Wait until lower layer association is finished */ + Semaphore_wait(self->receiveBufferMutex); + + CotpConnection_resetPayload(self->cotpConnection); + + while (true) { + + TpktState packetState; + + while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING) + { + Thread_sleep(1); + + if (self->stopHandlingThread) { + packetState = TPKT_ERROR; + break; + } + } + + if (packetState == TPKT_ERROR) + break; + + CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + if (cotpIndication == COTP_MORE_FRAGMENTS_FOLLOW) + continue; + + if (cotpIndication != COTP_DATA_INDICATION) + break; + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: parse message\n"); + + sessionIndication = + IsoSession_parseMessage(self->session, + CotpConnection_getPayload(self->cotpConnection)); + + if (sessionIndication != SESSION_DATA) { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: Invalid session message\n"); + break; + } + + if (!IsoPresentation_parseUserData(self->presentation, IsoSession_getUserData(self->session))) { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: Invalid presentation message\n"); + break; + } + + self->callback(ISO_IND_DATA, self->callbackParameter, + &(self->presentation->nextPayload)); + + /* wait for user to release the buffer */ + Semaphore_wait(self->receiveBufferMutex); + + CotpConnection_resetPayload(self->cotpConnection); + } + + self->callback(ISO_IND_CLOSED, self->callbackParameter, NULL); + + self->state = STATE_IDLE; + + Socket_destroy(self->socket); + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT_CONNECTION: exit connection %p\n", self); + + /* release buffer to enable resuse of client connection */ + Semaphore_post(self->receiveBufferMutex); + + self->handlingThreadRunning = false; +} + + +static void* +connectionThreadFunction(void* parameter) +{ + IsoClientConnection self = (IsoClientConnection) parameter; + + while (self->destroyHandlingThread == false) { + + if (self->startHandlingThread) { + self->startHandlingThread = false; + connectionHandlingThread(self); + } + + Thread_sleep(1); + } + + self->destroyHandlingThread = false; + + return NULL; +} + + +IsoClientConnection +IsoClientConnection_create(IsoIndicationCallback callback, void* callbackParameter) +{ + IsoClientConnection self = (IsoClientConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoClientConnection)); + + if (self == NULL) + return NULL; + + self->callback = callback; + self->callbackParameter = callbackParameter; + self->state = STATE_IDLE; + + self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE); + + self->transmitPayloadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + self->transmitPayloadBuffer->buffer = self->sendBuffer; + self->transmitPayloadBuffer->maxSize = ISO_CLIENT_BUFFER_SIZE; + + self->receivePayloadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + + self->transmitBufferMutex = Semaphore_create(1); + + self->receiveBufferMutex = Semaphore_create(1); + + self->receiveBuf = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE); + self->receiveBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + ByteBuffer_wrap(self->receiveBuffer, self->receiveBuf, 0, ISO_CLIENT_BUFFER_SIZE); + + self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation)); + + self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession)); + + self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpReadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + ByteBuffer_wrap(self->cotpReadBuffer, self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpWriteBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer)); + ByteBuffer_wrap(self->cotpWriteBuffer, self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection)); + + return self; +} + +void +IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters params, + ByteBuffer* payload, uint32_t connectTimeoutInMs) +{ + self->socket = TcpSocket_create(); + + Socket_setConnectTimeout(self->socket, connectTimeoutInMs); + + if (!Socket_connect(self->socket, params->hostname, params->tcpPort)) + goto returnError; + + /* COTP (ISO transport) handshake */ + CotpConnection_init(self->cotpConnection, self->socket, self->receiveBuffer, self->cotpReadBuffer, self->cotpWriteBuffer); + CotpIndication cotpIndication = + CotpConnection_sendConnectionRequestMessage(self->cotpConnection, params); + + TpktState packetState; + + uint64_t timeout = Hal_getTimeInMs() + CONFIG_TCP_READ_TIMEOUT_MS; + + while (((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING) + && (Hal_getTimeInMs() < timeout)) + { + Thread_sleep(1); + } + + if (packetState != TPKT_PACKET_COMPLETE) + goto returnError; + + cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + if (cotpIndication != COTP_CONNECT_INDICATION) + goto returnError; + + /* Upper layers handshake */ + struct sBufferChain sAcsePayload; + BufferChain acsePayload = &sAcsePayload; + acsePayload->buffer = payload->buffer; + acsePayload->partLength = payload->size; + acsePayload->length = payload->size; + acsePayload->nextPart = NULL; + + AcseConnection_init(&(self->acseConnection), NULL, NULL); + + AcseAuthenticationParameter authParameter = NULL; + + if (params != NULL) + authParameter = params->acseAuthParameter; + + struct sBufferChain sAcseBuffer; + BufferChain acseBuffer = &sAcseBuffer; + + acseBuffer->buffer = self->sendBuffer + payload->size; + acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acsePayload->length; + + AcseConnection_createAssociateRequestMessage(&(self->acseConnection), params, acseBuffer, acsePayload, + authParameter); + + struct sBufferChain sPresentationBuffer; + BufferChain presentationBuffer = &sPresentationBuffer; + + presentationBuffer->buffer = self->sendBuffer + acseBuffer->length; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length; + + IsoPresentation_init(self->presentation); + IsoPresentation_createConnectPdu(self->presentation, params, presentationBuffer, acseBuffer); + + struct sBufferChain sSessionBuffer; + BufferChain sessionBuffer = &sSessionBuffer; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length; + + IsoSession_init(self->session); + IsoSession_createConnectSpdu(self->session, params, sessionBuffer, + presentationBuffer); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + Semaphore_post(self->transmitBufferMutex); + + while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING) + { + Thread_sleep(1); + } + + cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + if (cotpIndication != COTP_DATA_INDICATION) + goto returnError; + + IsoSessionIndication sessionIndication; + + sessionIndication = + IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection)); + + if (sessionIndication != SESSION_CONNECT) { + if (DEBUG_ISO_CLIENT) + printf("IsoClientConnection_associate: no session connect indication\n"); + goto returnError; + } + + if (!IsoPresentation_parseAcceptMessage(self->presentation, IsoSession_getUserData(self->session))) { + if (DEBUG_ISO_CLIENT) + printf("IsoClientConnection_associate: no presentation ok indication\n"); + goto returnError; + } + + AcseIndication acseIndication; + + acseIndication = AcseConnection_parseMessage(&(self->acseConnection), &self->presentation->nextPayload); + + if (acseIndication != ACSE_ASSOCIATE) { + if (DEBUG_ISO_CLIENT) + printf("IsoClientConnection_associate: no ACSE_ASSOCIATE indication\n"); + goto returnError; + } + + + ByteBuffer_wrap(self->receivePayloadBuffer, self->acseConnection.userDataBuffer, + self->acseConnection.userDataBufferSize, self->acseConnection.userDataBufferSize); + + Semaphore_wait(self->receiveBufferMutex); + + self->callback(ISO_IND_ASSOCIATION_SUCCESS, self->callbackParameter, self->receivePayloadBuffer); + + /* wait for upper layer to release buffer */ + Semaphore_wait(self->receiveBufferMutex); + + self->state = STATE_ASSOCIATED; + + if (self->thread == NULL) { + self->thread = Thread_create(connectionThreadFunction, self, false); + Thread_start(self->thread); + } + + self->startHandlingThread = true; + + while (self->handlingThreadRunning == false) + Thread_sleep(1); + + return; + +returnError: + self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); + + self->state = STATE_ERROR; + + Socket_destroy(self->socket); + self->socket = NULL; + + Semaphore_post(self->transmitBufferMutex); //TODO check + + return; +} + +void +IsoClientConnection_sendMessage(IsoClientConnection self, ByteBuffer* payloadBuffer) +{ + + struct sBufferChain payloadBCMemory; + BufferChain payload = &payloadBCMemory; + + BufferChain_init(payload, payloadBuffer->size, payloadBuffer->size, NULL, payloadBuffer->buffer); + + struct sBufferChain presentationBCMemory; + BufferChain presentationBuffer = &presentationBCMemory; + + presentationBuffer->buffer = self->sendBuffer + payload->length; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE; + + IsoPresentation_createUserData(self->presentation, presentationBuffer, payload); + + struct sBufferChain sessionBufferBCMemory; + BufferChain sessionBuffer = &sessionBufferBCMemory; + + IsoSession_createDataSpdu(self->session, sessionBuffer, presentationBuffer); + + CotpIndication indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + /* release transmit buffer for use by API client */ + Semaphore_post(self->transmitBufferMutex); + + if (indication != COTP_OK) + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_sendMessage: send message failed!\n"); +} + +void +IsoClientConnection_close(IsoClientConnection self) +{ + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_close\n"); + + if (self->handlingThreadRunning) { + self->stopHandlingThread = true; + while (self->handlingThreadRunning) + Thread_sleep(1); + } + + self->state = STATE_IDLE; +} + + +void +IsoClientConnection_destroy(IsoClientConnection self) +{ + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_destroy\n"); + + if (self->state == STATE_ASSOCIATED) { + + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: call IsoClientConnection_close\n"); + + IsoClientConnection_close(self); + } + + /* stop handling thread */ + self->destroyHandlingThread = true; + + if (self->thread != NULL) { + while (self->destroyHandlingThread) + Thread_sleep(1); + + Thread_destroy(self->thread); + } + + if (self->receiveBuf != NULL) + GLOBAL_FREEMEM(self->receiveBuf); + if (self->receiveBuffer != NULL) + GLOBAL_FREEMEM(self->receiveBuffer); + if (self->cotpConnection != NULL) + GLOBAL_FREEMEM(self->cotpConnection); + + if (self->cotpReadBuffer != NULL) + GLOBAL_FREEMEM(self->cotpReadBuffer); + + if (self->cotpReadBuf != NULL) + GLOBAL_FREEMEM(self->cotpReadBuf); + + if (self->cotpWriteBuffer != NULL) + GLOBAL_FREEMEM(self->cotpWriteBuffer); + + if (self->cotpWriteBuf != NULL) + GLOBAL_FREEMEM(self->cotpWriteBuf); + + if (self->session != NULL) + GLOBAL_FREEMEM(self->session); + if (self->presentation != NULL) + GLOBAL_FREEMEM(self->presentation); + + GLOBAL_FREEMEM(self->transmitPayloadBuffer); + GLOBAL_FREEMEM(self->receivePayloadBuffer); + + Semaphore_destroy(self->receiveBufferMutex); + Semaphore_destroy(self->transmitBufferMutex); + + GLOBAL_FREEMEM(self->sendBuffer); + GLOBAL_FREEMEM(self); +} + +void +IsoClientConnection_abort(IsoClientConnection self) +{ + //TODO block other messages from being sent + IsoClientConnection_allocateTransmitBuffer(self); + + struct sBufferChain sAcseBuffer; + BufferChain acseBuffer = &sAcseBuffer; + acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE; + acseBuffer->buffer = self->sendBuffer; + acseBuffer->nextPart = NULL; + + AcseConnection_createAbortMessage(NULL, acseBuffer, false); + + struct sBufferChain sPresentationBuffer; + BufferChain presentationBuffer = &sPresentationBuffer; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length; + presentationBuffer->buffer = self->sendBuffer + acseBuffer->length; + presentationBuffer->nextPart = acseBuffer; + + IsoPresentation_createAbortUserMessage(self->presentation, presentationBuffer, acseBuffer); + + struct sBufferChain sSessionBuffer; + BufferChain sessionBuffer = &sSessionBuffer; + sessionBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - presentationBuffer->length; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length; + sessionBuffer->nextPart = presentationBuffer; + + IsoSession_createAbortSpdu(self->session, sessionBuffer, presentationBuffer); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + Semaphore_post(self->transmitBufferMutex); + + uint64_t timeout = Hal_getTimeInMs() + CONFIG_TCP_READ_TIMEOUT_MS; + + while ((self->handlingThreadRunning == true) && (Hal_getTimeInMs() < timeout)); +} + +void +IsoClientConnection_release(IsoClientConnection self) +{ + //TODO block other messages from being sent + IsoClientConnection_allocateTransmitBuffer(self); + + struct sBufferChain sAcseBuffer; + BufferChain acseBuffer = &sAcseBuffer; + acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE; + acseBuffer->buffer = self->sendBuffer; + acseBuffer->nextPart = NULL; + + AcseConnection_createReleaseRequestMessage(NULL, acseBuffer); + + struct sBufferChain sPresentationBuffer; + BufferChain presentationBuffer = &sPresentationBuffer; + presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length; + presentationBuffer->buffer = self->sendBuffer + acseBuffer->length; + presentationBuffer->nextPart = acseBuffer; + + IsoPresentation_createUserDataACSE(self->presentation, presentationBuffer, acseBuffer); + + struct sBufferChain sSessionBuffer; + BufferChain sessionBuffer = &sSessionBuffer; + sessionBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - presentationBuffer->length; + sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length; + sessionBuffer->nextPart = presentationBuffer; + + IsoSession_createFinishSpdu(NULL, sessionBuffer, presentationBuffer); + + CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); + + Semaphore_post(self->transmitBufferMutex); +} + + +ByteBuffer* +IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self) +{ + Semaphore_wait(self->transmitBufferMutex); + self->transmitPayloadBuffer->size = 0; + self->transmitPayloadBuffer->maxSize = ISO_CLIENT_BUFFER_SIZE; + return self->transmitPayloadBuffer; +} + +void +IsoClientConnection_releaseReceiveBuffer(IsoClientConnection self) +{ + Semaphore_post(self->receiveBufferMutex); +} diff --git a/src/mms/iso_common/iso_connection_parameters.c b/src/mms/iso_common/iso_connection_parameters.c index 2e71477a..8f4b2d2e 100644 --- a/src/mms/iso_common/iso_connection_parameters.c +++ b/src/mms/iso_common/iso_connection_parameters.c @@ -35,7 +35,7 @@ AcseAuthenticationParameter AcseAuthenticationParameter_create() { AcseAuthenticationParameter self = (AcseAuthenticationParameter) - calloc(1, sizeof(struct sAcseAuthenticationParameter)); + GLOBAL_CALLOC(1, sizeof(struct sAcseAuthenticationParameter)); return self; } @@ -45,9 +45,9 @@ AcseAuthenticationParameter_destroy(AcseAuthenticationParameter self) { if (self->mechanism == ACSE_AUTH_PASSWORD) if (self->value.password.octetString != NULL) - free(self->value.password.octetString); + GLOBAL_FREEMEM(self->value.password.octetString); - free(self); + GLOBAL_FREEMEM(self); } void @@ -67,7 +67,7 @@ AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, A IsoConnectionParameters IsoConnectionParameters_create() { - IsoConnectionParameters self = (IsoConnectionParameters) calloc(1, sizeof(struct sIsoConnectionParameters)); + IsoConnectionParameters self = (IsoConnectionParameters) GLOBAL_CALLOC(1, sizeof(struct sIsoConnectionParameters)); return self; } @@ -75,7 +75,7 @@ IsoConnectionParameters_create() void IsoConnectionParameters_destroy(IsoConnectionParameters self) { - free(self); + GLOBAL_FREEMEM(self); } void @@ -86,14 +86,14 @@ IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters s } void -IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, char* hostname, int tcpPort) +IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const char* hostname, int tcpPort) { self->hostname = hostname; self->tcpPort = tcpPort; } void -IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, char* apTitle, int aeQualifier) +IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier) { if (apTitle == NULL) self->remoteApTitleLen = 0; @@ -104,7 +104,7 @@ IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, char* apT } void -IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, uint16_t tSelector) +IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector) { self->remotePSelector = pSelector; self->remoteSSelector = sSelector; @@ -124,7 +124,7 @@ IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, char* apTi } void -IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, uint16_t tSelector) +IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector) { self->localPSelector = pSelector; self->localSSelector = sSelector; diff --git a/src/mms/iso_cotp/cotp.c b/src/mms/iso_cotp/cotp.c index 80e80a59..83089f01 100644 --- a/src/mms/iso_cotp/cotp.c +++ b/src/mms/iso_cotp/cotp.c @@ -3,10 +3,9 @@ * * ISO 8073 Connection Oriented Transport Protocol over TCP (RFC1006) * - * Partial implementation of the ISO 8073 COTP protocol for MMS. + * Partial implementation of the ISO 8073 COTP (ISO TP0) protocol for MMS. * - * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -28,11 +27,10 @@ #include "stack_config.h" #include "cotp.h" -#include "byte_stream.h" #include "byte_buffer.h" #include "buffer_chain.h" -#define COTP_RFC1006_HEADER_SIZE 4 +#define TPKT_RFC1006_HEADER_SIZE 4 #define COTP_DATA_HEADER_SIZE 3 @@ -46,8 +44,20 @@ #define DEBUG_COTP 0 #endif -static int -addPayloadToBuffer(CotpConnection* self, int rfc1006Length); +static bool +addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength); + +static inline uint16_t +getUint16(uint8_t* buffer) +{ + return (buffer[0] * 0x100) + buffer[1]; +} + +static inline uint8_t +getUint8(uint8_t* buffer) +{ + return buffer[0]; +} static void writeOptions(CotpConnection* self) @@ -56,28 +66,32 @@ writeOptions(CotpConnection* self) uint8_t* buffer = self->writeBuffer->buffer; int bufPos = self->writeBuffer->size; - if (self->options.tpdu_size != 0) { + if (self->options.tpduSize != 0) { if (DEBUG_COTP) printf("COTP: send TPDU size: %i\n", CotpConnection_getTpduSize(self)); buffer[bufPos++] = 0xc0; buffer[bufPos++] = 0x01; - buffer[bufPos++] = self->options.tpdu_size; + buffer[bufPos++] = self->options.tpduSize; } - if (self->options.tsap_id_dst != -1) { + if (self->options.tSelDst.size != 0) { buffer[bufPos++] = 0xc2; - buffer[bufPos++] = 0x02; - buffer[bufPos++] = (uint8_t) (self->options.tsap_id_dst / 0x100); - buffer[bufPos++] = (uint8_t) (self->options.tsap_id_dst & 0xff); + buffer[bufPos++] = (uint8_t) self->options.tSelDst.size; + + int i; + for (i = 0; i < self->options.tSelDst.size; i++) + buffer[bufPos++] = (uint8_t) self->options.tSelDst.value[i]; } - if (self->options.tsap_id_src != -1) { + if (self->options.tSelSrc.size != 0) { buffer[bufPos++] = 0xc1; - buffer[bufPos++] = 0x02; - buffer[bufPos++] = (uint8_t) (self->options.tsap_id_src / 0x100); - buffer[bufPos++] = (uint8_t) (self->options.tsap_id_src & 0xff); + buffer[bufPos++] = (uint8_t) self->options.tSelSrc.size; + + int i; + for (i = 0; i < self->options.tSelSrc.size; i++) + buffer[bufPos++] = (uint8_t) self->options.tSelSrc.value[i]; } self->writeBuffer->size = bufPos; @@ -87,12 +101,16 @@ static int getOptionsLength(CotpConnection* self) { int optionsLength = 0; - if (self->options.tpdu_size != 0) + + if (self->options.tpduSize != 0) optionsLength += 3; - if (self->options.tsap_id_dst != -1) - optionsLength += 4; - if (self->options.tsap_id_src != -1) - optionsLength += 4; + + if (self->options.tSelDst.size != 0) + optionsLength += (2 + self->options.tSelDst.size); + + if (self->options.tSelSrc.size != 0) + optionsLength += (2 + self->options.tSelSrc.size); + return optionsLength; } @@ -225,12 +243,12 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload) printf("COTP: Send COTP fragment %i bufpos: %i\n", fragments, currentBufPos); if (!sendBuffer(self)) - return ERROR; + return COTP_ERROR; fragments--; } - return OK; + return COTP_OK; } static void @@ -238,7 +256,7 @@ allocateWriteBuffer(CotpConnection* self) { if (self->writeBuffer == NULL ) self->writeBuffer = ByteBuffer_create(NULL, - CotpConnection_getTpduSize(self) + COTP_RFC1006_HEADER_SIZE); + CotpConnection_getTpduSize(self) + TPKT_RFC1006_HEADER_SIZE); } /* client side */ @@ -247,17 +265,22 @@ CotpConnection_sendConnectionRequestMessage(CotpConnection* self, IsoConnectionP { allocateWriteBuffer(self); - const int CON_REQUEST_SIZE = 22; + self->options.tSelDst = isoParameters->remoteTSelector; + self->options.tSelSrc = isoParameters->localTSelector; - if(self->writeBuffer->maxSize < CON_REQUEST_SIZE) - return ERROR; + int cotpRequestSize = getOptionsLength(self) + 6; + + int conRequestSize = cotpRequestSize + 5; + + if(self->writeBuffer->maxSize < conRequestSize) + return COTP_ERROR; uint8_t* buffer = self->writeBuffer->buffer; - writeRfc1006Header(self, CON_REQUEST_SIZE); + writeRfc1006Header(self, conRequestSize); /* LI */ - buffer[4] = 17; + buffer[4] = (uint8_t) cotpRequestSize; /* TPDU CODE */ buffer[5] = 0xe0; @@ -275,15 +298,12 @@ CotpConnection_sendConnectionRequestMessage(CotpConnection* self, IsoConnectionP self->writeBuffer->size = 11; - self->options.tsap_id_dst = isoParameters->remoteTSelector; - self->options.tsap_id_src = 0; - writeOptions(self); if (sendBuffer(self)) - return OK; + return COTP_OK; else - return ERROR; + return COTP_ERROR; } CotpIndication @@ -301,127 +321,134 @@ CotpConnection_sendConnectionResponseMessage(CotpConnection* self) writeOptions(self); if (sendBuffer(self)) - return OK; + return COTP_OK; else - return ERROR; + return COTP_ERROR; } -static int -parseOptions(CotpConnection* self, int opt_len) +static bool +parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen) { - int read_bytes = 0; - uint8_t option_type, option_len, uint8_value; - uint16_t uint16_value; - int i; - Socket sock = self->socket; - - while (read_bytes < opt_len) { - if (ByteStream_readUint8(sock, &option_type) == -1) - goto cpo_error; - if (ByteStream_readUint8(sock, &option_len) == -1) - goto cpo_error; + int bufPos = 0; + + while (bufPos < bufLen) { + uint8_t optionType = buffer[bufPos++]; + uint8_t optionLen = buffer[bufPos++]; - read_bytes += 2; + if (optionLen > (bufLen - bufPos)) { + if (DEBUG_COTP) + printf("COTP: option to long optionLen:%i bufPos:%i bufLen:%i\n", optionLen, bufPos, bufLen); + goto cpo_error; + } if (DEBUG_COTP) - printf("COTP: option: %02x len: %02x\n", option_type, option_len); + printf("COTP: option: %02x len: %02x\n", optionType, optionLen); - switch (option_type) { + switch (optionType) { case 0xc0: - { - if (ByteStream_readUint8(sock, &uint8_value) == -1) - goto cpo_error; - read_bytes++; + if (optionLen == 1) { + int requestedTpduSize = (1 << buffer[bufPos++]); - int requestedTpduSize = (1 << uint8_value); + CotpConnection_setTpduSize(self, requestedTpduSize); if (DEBUG_COTP) printf("COTP: requested TPDU size: %i\n", requestedTpduSize); - - CotpConnection_setTpduSize(self, requestedTpduSize); } + else + goto cpo_error; break; - case 0xc1: - if (option_len == 2) { - if (ByteStream_readUint16(sock, &uint16_value) == -1) - goto cpo_error; - read_bytes += 2; - self->options.tsap_id_src = (int32_t) uint16_value; - } else + + case 0xc1: /* remote T-selector */ + if (optionLen < 5) { + self->options.tSelSrc.size = optionLen; + + int i; + for (i = 0; i < optionLen; i++) + self->options.tSelSrc.value[i] = buffer[bufPos++]; + } + else goto cpo_error; break; - case 0xc2: - if (option_len == 2) { - if (ByteStream_readUint16(sock, &uint16_value) == -1) - goto cpo_error; - self->options.tsap_id_dst = (int32_t) uint16_value; - read_bytes += 2; - } else + + case 0xc2: /* local T-selector */ + if (optionLen < 5) { + self->options.tSelDst.size = optionLen; + + int i; + for (i = 0; i < optionLen; i++) + self->options.tSelDst.value[i] = buffer[bufPos++]; + } + else goto cpo_error; break; + case 0xc6: /* additional option selection */ - if (option_len == 1) { - ByteStream_readUint8(sock, &uint8_value); /* ignore value */ - read_bytes++; - } + if (optionLen == 1) + bufPos++; /* ignore value */ else goto cpo_error; break; - default: + default: if (DEBUG_COTP) - printf("COTP: Unknown option %02x\n", option_type); + printf("COTP: Unknown option %02x\n", optionType); - for (i = 0; i < opt_len; i++) { - if (ByteStream_readUint8(sock, &uint8_value) == -1) - goto cpo_error; - } - - read_bytes += opt_len; + bufPos += optionLen; /* ignore value */ break; } } - return 1; + return true; - cpo_error: +cpo_error: if (DEBUG_COTP) printf("COTP: cotp_parse_options: error parsing options!\n"); - return -1; + return false; } void CotpConnection_init(CotpConnection* self, Socket socket, - ByteBuffer* payloadBuffer) + ByteBuffer* payloadBuffer, ByteBuffer* readBuffer, ByteBuffer* writeBuffer) { self->state = 0; self->socket = socket; self->srcRef = -1; self->dstRef = -1; self->protocolClass = -1; - self->options.tpdu_size = 0; - self->options.tsap_id_src = -1; - self->options.tsap_id_dst = -1; + self->options.tpduSize = 0; + + TSelector tsel; + tsel.size = 2; + tsel.value[0] = 0; + tsel.value[1] = 1; + + self->options.tSelSrc = tsel; + self->options.tSelDst = tsel; self->payload = payloadBuffer; /* default TPDU size is maximum size */ CotpConnection_setTpduSize(self, COTP_MAX_TPDU_SIZE); - self->writeBuffer = NULL; + self->writeBuffer = writeBuffer; + self->readBuffer = readBuffer; + self->packetSize = 0; } -void -CotpConnection_destroy(CotpConnection* self) -{ - if (self->writeBuffer != NULL) - ByteBuffer_destroy(self->writeBuffer); -} +//void +//CotpConnection_destroy(CotpConnection* self) +//{ +// if (self->writeBuffer != NULL) +// ByteBuffer_destroy(self->writeBuffer); +// +// if (self->readBuffer != NULL) +// ByteBuffer_destroy(self->readBuffer); +//} int /* in byte */ CotpConnection_getTpduSize(CotpConnection* self) { - return (1 << self->options.tpdu_size); + return (1 << self->options.tpduSize); } void @@ -438,7 +465,7 @@ CotpConnection_setTpduSize(CotpConnection* self, int tpduSize /* in byte */) if ((1 << newTpduSize) > tpduSize) newTpduSize--; - self->options.tpdu_size = newTpduSize; + self->options.tpduSize = newTpduSize; } ByteBuffer* @@ -469,183 +496,202 @@ CotpConnection_getDstRef(CotpConnection* self) +--+------+---------+---------+---+---+------+-------+---------+ */ -static int -parseConnectRequestTpdu(CotpConnection* self, uint8_t len) + +static bool +parseConnectRequestTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) { - uint16_t dstRef; - uint16_t srcRef; - uint8_t protocolClass; - Socket sock = self->socket; + if (len < 6) + return false; - if (ByteStream_readUint16(sock, &dstRef) != 2) - return -1; - else - self->dstRef = dstRef; + self->dstRef = getUint16(buffer); + self->srcRef = getUint16(buffer + 2); + self->protocolClass = getUint8(buffer + 4); - if (ByteStream_readUint16(sock, &srcRef) != 2) - return -1; - else - self->srcRef = srcRef; + return parseOptions(self, buffer + 5, len - 6); +} - if (ByteStream_readUint8(sock, &protocolClass) != 1) - return -1; - else - self->protocolClass = protocolClass; +static bool +parseConnectConfirmTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) +{ + if (len < 6) + return false; + + self->srcRef = getUint16(buffer); + self->dstRef = getUint16(buffer + 2); + self->protocolClass = getUint8(buffer + 4); - return parseOptions(self, len - 6); + return parseOptions(self, buffer + 5, len - 6); } -static int -parseConnectConfirmTpdu(CotpConnection* self, uint8_t len) +static bool +parseDataTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len) { - uint16_t dstRef; - uint16_t srcRef; - uint8_t protocolClass; - Socket sock = self->socket; - - if (ByteStream_readUint16(sock, &dstRef) != 2) - return -1; - else - self->srcRef = dstRef; + if (len != 2) + return false; - if (ByteStream_readUint16(sock, &srcRef) != 2) - return -1; - else - self->dstRef = srcRef; + uint8_t flowControl = getUint8(buffer); - if (ByteStream_readUint8(sock, &protocolClass) != 1) - return -1; + if (flowControl & 0x80) + self->isLastDataUnit = true; else - self->protocolClass = protocolClass; + self->isLastDataUnit = false; - return parseOptions(self, len - 6); + return true; } -static int -parseDataTpdu(CotpConnection* self, uint8_t len) +static bool +addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength) { - uint8_t flowControl; + if (DEBUG_COTP) + printf("COTP: add to payload buffer (cur size: %i, len: %i)\n", self->payload->size, payloadLength); - if (len != 2) - return -1; + if ((self->payload->size + payloadLength) > self->payload->maxSize) + return false; - if (ByteStream_readUint8(self->socket, &flowControl) != 1) - return -1; - else { - if (flowControl & 0x80) - self->isLastDataUnit = true; - else - self->isLastDataUnit = false; - } + memcpy(self->payload->buffer + self->payload->size, buffer, payloadLength); - return 1; + self->payload->size += payloadLength; + + return true; } static CotpIndication -parseRFC1006Header(CotpConnection* self, uint16_t* rfc1006_length) +parseCotpMessage(CotpConnection* self) { - Socket sock = self->socket; - uint8_t b; + uint8_t* buffer = self->readBuffer->buffer + 4; + int tpduLength = self->readBuffer->size - 4; + + uint8_t len; + uint8_t tpduType; - if (ByteStream_readUint8(sock, &b) == -1) - return ERROR; - if (b != 3) - return ERROR; + len = buffer[0]; + assert(len <= tpduLength); - if (ByteStream_readUint8(sock, &b) == -1) - return ERROR; - if (b != 0) - return ERROR; + tpduType = buffer[1]; - if (ByteStream_readUint16(sock, rfc1006_length) == -1) - return ERROR; + switch (tpduType) { + case 0xe0: + if (parseConnectRequestTpdu(self, buffer + 2, len)) + return COTP_CONNECT_INDICATION; + else + return COTP_ERROR; + case 0xd0: + if (parseConnectConfirmTpdu(self, buffer + 2, len)) + return COTP_CONNECT_INDICATION; + else + return COTP_ERROR; + case 0xf0: + if (parseDataTpdu(self, buffer + 2, len)) { + + if (addPayloadToBuffer(self, buffer + 3, tpduLength - 3) != 1) + return COTP_ERROR; + + if (self->isLastDataUnit) + return COTP_DATA_INDICATION; + else + return COTP_MORE_FRAGMENTS_FOLLOW; + } + else + return COTP_ERROR; + default: + return COTP_ERROR; + } - return OK; } +CotpIndication +CotpConnection_parseIncomingMessage(CotpConnection* self) +{ + CotpIndication indication = parseCotpMessage(self); -static CotpIndication parseIncomingMessage(CotpConnection* self); + self->readBuffer->size = 0; + self->packetSize = 0; -static int -addPayloadToBuffer(CotpConnection* self, int rfc1006Length) + return indication; +} + +void +CotpConnection_resetPayload(CotpConnection* self) +{ + self->payload->size = 0; +} + +TpktState +CotpConnection_readToTpktBuffer(CotpConnection* self) { - int payloadLength = rfc1006Length - 7; + uint8_t* buffer = self->readBuffer->buffer; + int bufferSize = self->readBuffer->maxSize; + int bufPos = self->readBuffer->size; - if ((self->payload->size + payloadLength) > self->payload->maxSize) - return 0; + assert (bufferSize > 4); - int readLength = ByteStream_readOctets(self->socket, - self->payload->buffer + self->payload->size, - payloadLength); + int readBytes; - if (readLength != payloadLength) { - if (DEBUG_COTP) - printf("COTP: read %i bytes should have been %i\n", readLength, payloadLength); - return 0; - } - else { - self->payload->size += payloadLength; + if (bufPos < 4) { - if (self->isLastDataUnit == false) { - if (parseIncomingMessage(self) == DATA_INDICATION) - return 1; - else - return 0; + readBytes = Socket_read(self->socket, buffer + bufPos, 4 - bufPos); + + if (readBytes < 0) + goto exit_closed; + + if (DEBUG_COTP) { + if (readBytes > 0) + printf("TPKT: read %i bytes from socket\n", readBytes); } - else - return 1; - } -} -static CotpIndication -parseIncomingMessage(CotpConnection* self) -{ - uint8_t len; - uint8_t tpduType; - uint16_t rfc1006Length; - Socket sock = self->socket; + bufPos += readBytes; - if (parseRFC1006Header(self, &rfc1006Length) == ERROR) - return ERROR; + if (bufPos == 4) { + if ((buffer[0] == 3) && (buffer[1] == 0)) { + self->packetSize = (buffer[2] * 0x100) + buffer[3]; - if (ByteStream_readUint8(sock, &len) != 1) { - return ERROR; - } + if (DEBUG_COTP) + printf("TPKT: header complete (msg size = %i)\n", self->packetSize); - if (ByteStream_readUint8(sock, &tpduType) == 1) { - switch (tpduType) { - case 0xe0: - if (parseConnectRequestTpdu(self, len) == 1) - return CONNECT_INDICATION; - else - return ERROR; - case 0xd0: - self->isLastDataUnit = true; - if (parseConnectConfirmTpdu(self, len) == 1) - return CONNECT_INDICATION; - else - return ERROR; - case 0xf0: - if (parseDataTpdu(self, len) == 1) { - if (addPayloadToBuffer(self, rfc1006Length) == 1) - return DATA_INDICATION; - else - return ERROR; + if (self->packetSize > bufferSize) { + if (DEBUG_COTP) printf("TPKT: packet too large\n"); + goto exit_error; + } + } + else { + if (DEBUG_COTP) printf("TPKT: failed to decode TPKT header.\n"); + goto exit_error; } - else - return ERROR; - default: - return ERROR; } + else + goto exit_waiting; } - else - return ERROR; -} -CotpIndication -CotpConnection_parseIncomingMessage(CotpConnection* self) -{ - self->payload->size = 0; + readBytes = Socket_read(self->socket, buffer + bufPos, self->packetSize - bufPos); + + if (readBytes < 0) + goto exit_closed; + + bufPos += readBytes; + + if (bufPos < self->packetSize) + goto exit_waiting; - return parseIncomingMessage(self); + if (DEBUG_COTP) printf("TPKT: message complete (size = %i)\n", self->packetSize); + + self->readBuffer->size = bufPos; + return TPKT_PACKET_COMPLETE; + +exit_closed: + if (DEBUG_COTP) printf("TPKT: socket closed or socket error\n"); + return TPKT_ERROR; + +exit_error: + if (DEBUG_COTP) printf("TPKT: Error parsing message\n"); + return TPKT_ERROR; + +exit_waiting: + + if (DEBUG_COTP) + if (bufPos != 0) + printf("TPKT: waiting (read %i of %i)\n", bufPos, self->packetSize); + + self->readBuffer->size = bufPos; + return TPKT_WAITING; } + diff --git a/src/mms/iso_mms/asn1c/GeneralizedTime.c b/src/mms/iso_mms/asn1c/GeneralizedTime.c index 80341811..cf974496 100644 --- a/src/mms/iso_mms/asn1c/GeneralizedTime.c +++ b/src/mms/iso_mms/asn1c/GeneralizedTime.c @@ -14,6 +14,23 @@ #include #endif /* __CYGWIN__ */ +#ifdef __IAR_SYSTEMS_ICC__ + +static struct tm *localtime_r(const time_t *tloc, struct tm *result) { + struct tm *tm; + if((tm = localtime(tloc))) + return memcpy(result, tm, sizeof(struct tm)); + return 0; +} + +static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { + struct tm *tm; + if((tm = gmtime(tloc))) + return memcpy(result, tm, sizeof(struct tm)); + return 0; +} +#endif /* __IAR_SYSTEMS_ICC__ */ + #if defined(WIN32) #pragma message( "PLEASE STOP AND READ!") #pragma message( " localtime_r is implemented via localtime(), which may be not thread-safe.") diff --git a/src/mms/iso_mms/asn1c/INTEGER.c b/src/mms/iso_mms/asn1c/INTEGER.c index 53a64285..c1d074f5 100644 --- a/src/mms/iso_mms/asn1c/INTEGER.c +++ b/src/mms/iso_mms/asn1c/INTEGER.c @@ -6,7 +6,7 @@ #include #include #include /* Encoder and decoder of a primitive type */ -#include +//#include /* * INTEGER basic type description. @@ -95,8 +95,6 @@ INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr, return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key); } -static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop); - #if 0 /* * INTEGER specific human-readable output. @@ -220,6 +218,7 @@ INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, } #endif +#if 0 struct e2v_key { const char *start; const char *stop; @@ -245,6 +244,7 @@ INTEGER__compar_enum2value(const void *kp, const void *am) { return name[0] ? -1 : 0; } + static const asn_INTEGER_enum_map_t * INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { asn_INTEGER_enum_map_t *el_found; @@ -282,7 +282,9 @@ INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const } return el_found; } +#endif +#if 0 static int INTEGER__compar_value2enum(const void *kp, const void *am) { long a = *(const long *)kp; @@ -301,7 +303,9 @@ INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { count, sizeof(specs->value2enum[0]), INTEGER__compar_value2enum); } +#endif +#if 0 static int INTEGER_st_prealloc(INTEGER_t *st, int min_size) { void *p = MALLOC(min_size + 1); @@ -315,6 +319,7 @@ INTEGER_st_prealloc(INTEGER_t *st, int min_size) { return -1; } } +#endif #if 0 /* @@ -737,7 +742,7 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { /* Sanity checking */ if(!iptr || !iptr->buf || !lptr) { - errno = EINVAL; + //errno = EINVAL; return -1; } @@ -766,7 +771,7 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { size = end - b; if(size > sizeof(long)) { /* Still cannot fit the long */ - errno = ERANGE; + //errno = ERANGE; return -1; } } @@ -799,7 +804,7 @@ asn_long2INTEGER(INTEGER_t *st, long value) { int add; if(!st) { - errno = EINVAL; + //errno = EINVAL; return -1; } diff --git a/src/mms/iso_mms/asn1c/NativeEnumerated.c b/src/mms/iso_mms/asn1c/NativeEnumerated.c index 76269a35..76aab81b 100644 --- a/src/mms/iso_mms/asn1c/NativeEnumerated.c +++ b/src/mms/iso_mms/asn1c/NativeEnumerated.c @@ -27,7 +27,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { NativeInteger_decode_ber, NativeInteger_encode_der, NULL, - NativeEnumerated_encode_xer, + NULL, + //NativeEnumerated_encode_xer, NativeEnumerated_decode_uper, NativeEnumerated_encode_uper, 0, /* Use generic outmost tag fetcher */ @@ -40,6 +41,7 @@ asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { 0 /* No specifics */ }; +#if 0 asn_enc_rval_t NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, int ilevel, enum xer_encoder_flags_e flags, @@ -69,6 +71,7 @@ NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, _ASN_ENCODE_FAILED; } } +#endif asn_dec_rval_t NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, diff --git a/src/mms/iso_mms/asn1c/asn_internal.h b/src/mms/iso_mms/asn1c/asn_internal.h index fc5ee818..2ba232bc 100644 --- a/src/mms/iso_mms/asn1c/asn_internal.h +++ b/src/mms/iso_mms/asn1c/asn_internal.h @@ -11,6 +11,9 @@ #include "asn_application.h" /* Application-visible API */ +//#include "libiec61850_platform_includes.h" +#include "lib_memory.h" + #ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ #include /* for assert() macro */ #endif @@ -23,10 +26,23 @@ extern "C" { #define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */ int get_asn1c_environment_version(void); /* Run-time version */ +#if 0 +#ifndef CALLOC #define CALLOC(nmemb, size) calloc(nmemb, size) +#endif + +#ifndef MALLOC #define MALLOC(size) malloc(size) +#endif + +#ifndef REALLOC #define REALLOC(oldptr, size) realloc(oldptr, size) +#endif + +#ifndef FREEMEM #define FREEMEM(ptr) free(ptr) +#endif +#endif /* * A macro for debugging the ASN.1 internals. diff --git a/src/mms/iso_mms/asn1c/asn_system.h b/src/mms/iso_mms/asn1c/asn_system.h index 61c41512..0fdb37fa 100644 --- a/src/mms/iso_mms/asn1c/asn_system.h +++ b/src/mms/iso_mms/asn1c/asn_system.h @@ -1,110 +1,119 @@ -/*- - * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. - * Redistribution and modifications are permitted subject to BSD license. - */ -/* - * Miscellaneous system-dependent types. - */ -#ifndef _ASN_SYSTEM_H_ -#define _ASN_SYSTEM_H_ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include /* For snprintf(3) */ -#include /* For *alloc(3) */ -#include /* For memcpy(3) */ -#include /* For size_t */ -#include /* For va_start */ -#include /* for offsetof and ptrdiff_t */ - -#ifdef _WIN32 -#ifndef WIN32 -#define WIN32 -#endif -#endif - -#ifdef WIN32 - -#include -#include -#define snprintf _snprintf -#define vsnprintf _vsnprintf - -#ifdef _MSC_VER /* MSVS.Net */ -#ifndef __cplusplus -#define inline __inline -#endif -#define ssize_t SSIZE_T -//typedef char int8_t; -//typedef short int16_t; -//typedef int int32_t; -//typedef unsigned char uint8_t; -//typedef unsigned short uint16_t; -//typedef unsigned int uint32_t; -#define WIN32_LEAN_AND_MEAN -#include -#include -#define isnan _isnan -#define finite _finite -#define copysign _copysign -#define ilogb _logb -#endif /* _MSC_VER */ - -#else /* !WIN32 */ - -#if defined(__vxworks) -#include -#else /* !defined(__vxworks) */ - -#include /* C99 specifies this file */ -/* - * 1. Earlier FreeBSD version didn't have , - * but was present. - * 2. Sun Solaris requires for alloca(3), - * but does not have . - */ -#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) -#if defined(sun) -#include /* For alloca(3) */ -#include /* for finite(3) */ -#elif defined(__hpux) -#ifdef __GNUC__ -#include /* For alloca(3) */ -#else /* !__GNUC__ */ -#define inline -#endif /* __GNUC__ */ -#else -#include /* SUSv2+ and C99 specify this file, for uintXX_t */ -#endif /* defined(sun) */ -#endif - -#endif /* defined(__vxworks) */ - -#endif /* WIN32 */ - -#if __GNUC__ >= 3 -#ifndef GCC_PRINTFLIKE -#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) -#endif -#else -#ifndef GCC_PRINTFLIKE -#define GCC_PRINTFLIKE(fmt,var) /* nothing */ -#endif -#endif - -#ifndef offsetof /* If not defined by */ -#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) -#endif /* offsetof */ - -#ifndef MIN /* Suitable for comparing primitive types (integers) */ -#if defined(__GNUC__) -#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ - ((_a)<(_b)?(_a):(_b)); }) -#else /* !__GNUC__ */ -#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ -#endif /* __GNUC__ */ -#endif /* MIN */ - -#endif /* _ASN_SYSTEM_H_ */ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Miscellaneous system-dependent types. + */ +#ifndef _ASN_SYSTEM_H_ +#define _ASN_SYSTEM_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* For snprintf(3) */ +#include /* For *alloc(3) */ +#include /* For memcpy(3) */ + +#include "stack_config.h" +#if CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS +#include "libiec61850_platform_specific.h" +#else +#include /* For size_t */ +#endif + +#include /* For va_start */ +#include /* for offsetof and ptrdiff_t */ + + + +#ifdef _WIN32 +#ifndef WIN32 +#define WIN32 +#endif +#endif + +#ifdef WIN32 + +#include +#include +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +#ifdef _MSC_VER /* MSVS.Net */ +#ifndef __cplusplus +#define inline __inline +#endif +#define ssize_t SSIZE_T +//typedef char int8_t; +//typedef short int16_t; +//typedef int int32_t; +//typedef unsigned char uint8_t; +//typedef unsigned short uint16_t; +//typedef unsigned int uint32_t; +#define WIN32_LEAN_AND_MEAN +#include +#include +#define isnan _isnan +#define finite _finite +#define copysign _copysign +#define ilogb _logb +#endif /* _MSC_VER */ + +#else /* !WIN32 */ + +#if defined(__vxworks) +#include +#else /* !defined(__vxworks) */ + +#include /* C99 specifies this file */ +/* + * 1. Earlier FreeBSD version didn't have , + * but was present. + * 2. Sun Solaris requires for alloca(3), + * but does not have . + */ +#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) +#if defined(sun) +#include /* For alloca(3) */ +#include /* for finite(3) */ +#elif defined(__hpux) +#ifdef __GNUC__ +#include /* For alloca(3) */ +#else /* !__GNUC__ */ +#define inline +#endif /* __GNUC__ */ +#else +#include /* SUSv2+ and C99 specify this file, for uintXX_t */ +#endif /* defined(sun) */ +#endif + +#endif /* defined(__vxworks) */ + +#endif /* WIN32 */ + +#if __GNUC__ >= 3 +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +#endif +#else +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt,var) /* nothing */ +#endif +#endif + +#ifndef offsetof /* If not defined by */ +#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) +#endif /* offsetof */ + +#ifndef MIN /* Suitable for comparing primitive types (integers) */ +#if defined(__GNUC__) +#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ + ((_a)<(_b)?(_a):(_b)); }) +#else /* !__GNUC__ */ +#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ +#endif /* __GNUC__ */ +#endif /* MIN */ + +#endif /* _ASN_SYSTEM_H_ */ diff --git a/src/mms/iso_mms/asn1c/der_encoder.c b/src/mms/iso_mms/asn1c/der_encoder.c index 6c859e1b..cc2000e0 100644 --- a/src/mms/iso_mms/asn1c/der_encoder.c +++ b/src/mms/iso_mms/asn1c/der_encoder.c @@ -80,20 +80,18 @@ der_write_tags(asn_TYPE_descriptor_t *sd, ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ asn_app_consume_bytes_f *cb, void *app_key) { - ber_tlv_tag_t *tags; /* Copy of tags stream */ + ber_tlv_tag_t tag_mem[5]; /* Copy of tags stream */ + ber_tlv_tag_t* tags; int tags_count; /* Number of tags */ size_t overall_length; - ssize_t *lens; + ssize_t lens[5]; int i; - ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)", - sd->name, tag_mode, sd->tags_count, - ber_tlv_tag_string(tag), - tag_mode - ?(sd->tags_count+1 - -((tag_mode == -1) && sd->tags_count)) - :sd->tags_count - ); + if (sd->tags_count > 4) { + printf("TO MUCH TAGS"); + errno = ENOMEM; + return -1; + } if(tag_mode) { /* @@ -102,11 +100,9 @@ der_write_tags(asn_TYPE_descriptor_t *sd, * and initialize it appropriately. */ int stag_offset; - tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); - if(!tags) { /* Can fail on !x86 */ - errno = ENOMEM; - return -1; - } + + tags = tag_mem; + tags_count = sd->tags_count + 1 /* EXPLICIT or IMPLICIT tag is given */ - ((tag_mode == -1) && sd->tags_count); @@ -124,12 +120,6 @@ der_write_tags(asn_TYPE_descriptor_t *sd, if(tags_count == 0) return 0; - lens = (ssize_t *)alloca(tags_count * sizeof(lens[0])); - if(!lens) { - errno = ENOMEM; - return -1; - } - /* * Array of tags is initialized. * Now, compute the size of the TLV pairs, from right to left. diff --git a/src/mms/iso_mms/asn1c/xer_encoder.h b/src/mms/iso_mms/asn1c/xer_encoder.h index 055e73c0..1cb546a3 100644 --- a/src/mms/iso_mms/asn1c/xer_encoder.h +++ b/src/mms/iso_mms/asn1c/xer_encoder.h @@ -1,59 +1,59 @@ -/*- - * Copyright (c) 2004 Lev Walkin . All rights reserved. - * Redistribution and modifications are permitted subject to BSD license. - */ -#ifndef _XER_ENCODER_H_ -#define _XER_ENCODER_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct asn_TYPE_descriptor_s; /* Forward declaration */ - -/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ -enum xer_encoder_flags_e { - /* Mode of encoding */ - XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ - XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ -}; - -/* - * The XER encoder of any type. May be invoked by the application. - */ -asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - enum xer_encoder_flags_e xer_flags, - asn_app_consume_bytes_f *consume_bytes_cb, - void *app_key /* Arbitrary callback argument */ - ); - -/* - * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) - * output into the chosen file pointer. - * RETURN VALUES: - * 0: The structure is printed. - * -1: Problem printing the structure. - * WARNING: No sensible errno value is returned. - */ -int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); - -/* - * Type of the generic XER encoder. - */ -typedef asn_enc_rval_t (xer_type_encoder_f)( - struct asn_TYPE_descriptor_s *type_descriptor, - void *struct_ptr, /* Structure to be encoded */ - int ilevel, /* Level of indentation */ - enum xer_encoder_flags_e xer_flags, - asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ - void *app_key /* Arbitrary callback argument */ - ); - -#ifdef __cplusplus -} -#endif - -#endif /* _XER_ENCODER_H_ */ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_ENCODER_H_ +#define _XER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ +enum xer_encoder_flags_e { + /* Mode of encoding */ + XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ + XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ +}; + +/* + * The XER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); + +/* + * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) + * output into the chosen file pointer. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem printing the structure. + * WARNING: No sensible errno value is returned. + */ +int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); + +/* + * Type of the generic XER encoder. + */ +typedef asn_enc_rval_t (xer_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int ilevel, /* Level of indentation */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_ENCODER_H_ */ diff --git a/src/mms/iso_mms/client/mms_client_common.c b/src/mms/iso_mms/client/mms_client_common.c index e0f02925..f06072e6 100644 --- a/src/mms/iso_mms/client/mms_client_common.c +++ b/src/mms/iso_mms/client/mms_client_common.c @@ -49,7 +49,7 @@ mmsClient_getInvokeId(ConfirmedResponsePdu_t* confirmedResponse) MmsPdu_t* mmsClient_createConfirmedRequestPdu(uint32_t invokeId) { - MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t)); + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); mmsPdu->present = MmsPdu_PR_confirmedRequestPdu; asn_long2INTEGER(&(mmsPdu->choice.confirmedRequestPdu.invokeID), invokeId); diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index c41c7dae..793d50d7 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -1,7 +1,7 @@ /* * mms_client_connection.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -36,6 +36,7 @@ #include #define CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT 5000 +#define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000 #define OUTSTANDING_CALLS 10 static void @@ -45,7 +46,7 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) MmsPdu_t* mmsPdu = 0; /* allow asn1c to allocate structure */ if (DEBUG_MMS_CLIENT) - printf("MMS_CLIENT: report handler revd size:%i\n", ByteBuffer_getSize(message)); + printf("MMS_CLIENT: report handler rcvd size:%i\n", ByteBuffer_getSize(message)); asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); @@ -58,7 +59,7 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) if (mmsPdu->choice.unconfirmedPDU.unconfirmedService.present == UnconfirmedService_PR_informationReport) - { + { char* domainId = NULL; InformationReport_t* report = @@ -84,18 +85,15 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) self->reportHandler(self->reportHandlerParameter, domainId, variableListName, values, true); - free(variableListName); + GLOBAL_FREEMEM(variableListName); } else { // Ignore domain and association specific information reports (not used by IEC 61850) } } - else if (report->variableAccessSpecification.present == - VariableAccessSpecification_PR_listOfVariable) - { - //TODO add code to handle reports with more than one variable - + else if (report->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) + { int listSize = report->listOfAccessResult.list.count; int variableSpecSize = report->variableAccessSpecification.choice.listOfVariable.list.count; @@ -111,12 +109,11 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) int i; for (i = 0; i < variableSpecSize; i++) { if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification.present - == - VariableSpecification_PR_name) - { + == VariableSpecification_PR_name) + { if (report->variableAccessSpecification.choice.listOfVariable.list.array[i] - ->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) { - + ->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) + { int nameSize = report->variableAccessSpecification.choice.listOfVariable.list.array[i] ->variableSpecification.choice.name.choice.vmdspecific.size; @@ -130,14 +127,20 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) memcpy(variableListName, buffer, nameSize); variableListName[nameSize] = 0; + MmsValue* value = values; + + if (variableSpecSize != 1) + value = MmsValue_getElement(values, i); + self->reportHandler(self->reportHandlerParameter, domainId, variableListName, - values, false); + value, false); // report handler should have deleted the MmsValue! - values = NULL; + if (variableSpecSize != 1) + MmsValue_setElement(values, i, NULL); + else + values = NULL; } - else - MmsValue_delete(values); } else if (report->variableAccessSpecification.choice.listOfVariable.list.array[i] ->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) { @@ -167,22 +170,25 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) memcpy(itemNameStr, itemNamebuffer, itemNameSize); itemNameStr[itemNameSize] = 0; + MmsValue* value = values; + + if (variableSpecSize != 1) + value = MmsValue_getElement(values, i); + self->reportHandler(self->reportHandlerParameter, domainNameStr, itemNameStr, - values, false); + value, false); // report handler should have deleted the MmsValue! - values = NULL; + if (variableSpecSize != 1) + MmsValue_setElement(values, i, NULL); + else + values = NULL; + } - else - MmsValue_delete(values); } - } - } - //TODO handle CommandTermination request! - if (values != NULL) MmsValue_delete(values); } @@ -615,7 +621,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) } self->lastResponse = payload; - return; + IsoClientConnection_releaseReceiveBuffer(self->isoClient); } else if (tag == 0xa3) { /* unconfirmed PDU */ handleUnconfirmedMmsPdu(self, payload); @@ -627,7 +633,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) self->concludeState = CONCLUDE_STATE_REQUESTED; - /* block all new user requests */ + /* TODO block all new user requests */ + IsoClientConnection_releaseReceiveBuffer(self->isoClient); } else if (tag == 0x8c) { /* conclude response PDU */ @@ -742,7 +749,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) MmsConnection MmsConnection_create() { - MmsConnection self = (MmsConnection) calloc(1, sizeof(struct sMmsConnection)); + MmsConnection self = (MmsConnection) GLOBAL_CALLOC(1, sizeof(struct sMmsConnection)); self->parameters.dataStructureNestingLevel = -1; self->parameters.maxServOutstandingCalled = -1; @@ -759,16 +766,23 @@ MmsConnection_create() self->lastResponseError = MMS_ERROR_NONE; - self->outstandingCalls = (uint32_t*) calloc(OUTSTANDING_CALLS, sizeof(uint32_t)); + self->outstandingCalls = (uint32_t*) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(uint32_t)); self->isoParameters = IsoConnectionParameters_create(); /* Load default values for connection parameters */ - IsoConnectionParameters_setLocalAddresses(self->isoParameters, 1, 1, 1); + TSelector selector1 = { 2, { 0, 0 } }; + TSelector selector2 = { 2, { 0, 0 } }; + + IsoConnectionParameters_setLocalAddresses(self->isoParameters, 1, 1, selector1); IsoConnectionParameters_setLocalApTitle(self->isoParameters, "1.1.1.999", 12); - IsoConnectionParameters_setRemoteAddresses(self->isoParameters, 1, 1, 1); + IsoConnectionParameters_setRemoteAddresses(self->isoParameters, 1, 1, selector2); IsoConnectionParameters_setRemoteApTitle(self->isoParameters, "1.1.1.999.1", 12); + self->connectTimeout = CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT; + + self->isoClient = IsoClientConnection_create((IsoIndicationCallback) mmsIsoCallback, (void*) self); + return self; } @@ -785,9 +799,9 @@ MmsConnection_destroy(MmsConnection self) Semaphore_destroy(self->lastResponseLock); Semaphore_destroy(self->outstandingCallsLock); - free(self->outstandingCalls); + GLOBAL_FREEMEM(self->outstandingCalls); - free(self); + GLOBAL_FREEMEM(self); } void @@ -803,6 +817,12 @@ MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs) self->requestTimeout = timeoutInMs; } +void +MmsConnection_setConnectTimeout(MmsConnection self, uint32_t timeoutInMs) +{ + self->connectTimeout = timeoutInMs; +} + void MmsConnection_setLocalDetail(MmsConnection self, int32_t localDetail) { @@ -842,10 +862,8 @@ waitForConnectResponse(MmsConnection self) } bool -MmsConnection_connect(MmsConnection self, MmsError* mmsError, char* serverName, int serverPort) +MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort) { - self->isoClient = IsoClientConnection_create((IsoIndicationCallback) mmsIsoCallback, (void*) self); - IsoConnectionParameters_setTcpParameters(self->isoParameters, serverName, serverPort); if (self->parameters.maxPduSize == -1) @@ -857,7 +875,8 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, char* serverName, self->connectionState = MMS_CON_WAITING; - IsoClientConnection_associate(self->isoClient, self->isoParameters, payload); + IsoClientConnection_associate(self->isoClient, self->isoParameters, payload, + self->connectTimeout); waitForConnectResponse(self); @@ -890,12 +909,26 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, char* serverName, } } +void +MmsConnection_close(MmsConnection self) +{ + self->connectionLostHandler = NULL; + + if (self->associationState == MMS_STATE_CONNECTED) + IsoClientConnection_close(self->isoClient); +} + void MmsConnection_abort(MmsConnection self, MmsError* mmsError) { *mmsError = MMS_ERROR_NONE; - IsoClientConnection_abort(self->isoClient); + self->connectionLostHandler = NULL; + + if (self->associationState == MMS_STATE_CONNECTED) + IsoClientConnection_abort(self->isoClient); + + //TODO wait for connection to be closed } static void @@ -960,6 +993,8 @@ MmsConnection_conclude(MmsConnection self, MmsError* mmsError) if (self->concludeState == CONCLUDE_STATE_REJECTED) *mmsError = MMS_ERROR_CONCLUDE_REJECTED; } + + self->connectionLostHandler = NULL; } void @@ -975,10 +1010,10 @@ mmsClient_getNameListSingleRequest( LinkedList* nameList, MmsConnection self, MmsError* mmsError, - char* domainId, + const char* domainId, MmsObjectClass objectClass, bool associationSpecific, - char* continueAfter) + const char* continueAfter) { *mmsError = MMS_ERROR_NONE; @@ -1016,7 +1051,7 @@ mmsClient_getNameListSingleRequest( static LinkedList /* */ mmsClient_getNameList(MmsConnection self, MmsError *mmsError, - char* domainId, + const char* domainId, MmsObjectClass objectClass, bool associationSpecific) { @@ -1055,13 +1090,13 @@ MmsConnection_getDomainNames(MmsConnection self, MmsError* mmsError) } LinkedList /* */ -MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, char* domainId) +MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, const char* domainId) { return mmsClient_getNameList(self, mmsError, domainId, MMS_NAMED_VARIABLE, false); } LinkedList /* */ -MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, char* domainId) +MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, const char* domainId) { return mmsClient_getNameList(self, mmsError, domainId, MMS_NAMED_VARIABLE_LIST, false); } @@ -1074,7 +1109,7 @@ MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsErr MmsValue* MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, - char* domainId, char* itemId) + const char* domainId, const char* itemId) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1103,7 +1138,7 @@ MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, MmsValue* MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, - char* domainId, char* itemId, + const char* domainId, const char* itemId, uint32_t startIndex, uint32_t numberOfElements) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1134,7 +1169,7 @@ MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, MmsValue* MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, - char* domainId, LinkedList /**/items) + const char* domainId, LinkedList /**/items) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1163,7 +1198,7 @@ MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, MmsValue* MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError, - char* domainId, char* listName, + const char* domainId, const char* listName, bool specWithResult) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1197,7 +1232,7 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError MmsValue* MmsConnection_readNamedVariableListValuesAssociationSpecific( MmsConnection self, MmsError* mmsError, - char* listName, + const char* listName, bool specWithResult) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1228,7 +1263,7 @@ MmsConnection_readNamedVariableListValuesAssociationSpecific( LinkedList /* */ MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError, - char* domainId, char* listName, bool* deletable) + const char* domainId, const char* listName, bool* deletable) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1259,7 +1294,7 @@ MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsEr LinkedList /* */ MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection self, MmsError* mmsError, - char* listName, bool* deletable) + const char* listName, bool* deletable) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1290,7 +1325,7 @@ MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection se void MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError, - char* domainId, char* listName, LinkedList variableSpecs) + const char* domainId, const char* listName, LinkedList variableSpecs) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1317,7 +1352,7 @@ MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError, void MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self, - MmsError* mmsError, char* listName, LinkedList variableSpecs) + MmsError* mmsError, const char* listName, LinkedList variableSpecs) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1344,7 +1379,7 @@ MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self, void MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError, - char* domainId, char* listName) + const char* domainId, const char* listName) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1370,7 +1405,7 @@ MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError, void MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self, - MmsError* mmsError, char* listName) + MmsError* mmsError, const char* listName) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1397,7 +1432,7 @@ MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self, MmsVariableSpecification* MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError, - char* domainId, char* itemId) + const char* domainId, const char* itemId) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1483,7 +1518,7 @@ MmsConnection_getServerStatus(MmsConnection self, MmsError* mmsError, int* vmdLo int32_t -MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, char* filename, uint32_t initialPosition, +MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filename, uint32_t initialPosition, uint32_t* fileSize, uint64_t* lastModified) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1538,7 +1573,7 @@ MmsConnection_fileClose(MmsConnection self, MmsError* mmsError, int32_t frsmId) } void -MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, char* fileName) +MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, const char* fileName) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1594,7 +1629,7 @@ MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, M bool -MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, char* fileSpecification, char* continueAfter, +MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, const char* fileSpecification, const char* continueAfter, MmsFileDirectoryHandler handler, void* handlerParameter) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1625,7 +1660,7 @@ MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, char* fil } void -MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, char* currentFileName, char* newFileName) +MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, const char* currentFileName, const char* newFileName) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1651,7 +1686,7 @@ MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, char* currentFi void MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError, - char* domainId, char* itemId, + const char* domainId, const char* itemId, MmsValue* value) { ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); @@ -1676,7 +1711,7 @@ MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError, } void -MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, char* domainId, +MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId, LinkedList /**/items, LinkedList /* */values, /* OUTPUT */LinkedList* /* */accessResults) @@ -1711,22 +1746,22 @@ void MmsServerIdentity_destroy(MmsServerIdentity* self) { if (self->modelName != NULL) - free(self->modelName); + GLOBAL_FREEMEM(self->modelName); if (self->vendorName != NULL) - free(self->vendorName); + GLOBAL_FREEMEM(self->vendorName); if (self->revision != NULL) - free(self->revision); + GLOBAL_FREEMEM(self->revision); - free(self); + GLOBAL_FREEMEM(self); } MmsVariableAccessSpecification* MmsVariableAccessSpecification_create(char* domainId, char* itemId) { MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*) - malloc(sizeof(MmsVariableAccessSpecification)); + GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification)); self->domainId = domainId; self->itemId = itemId; @@ -1741,7 +1776,7 @@ MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemI char* componentName) { MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*) - malloc(sizeof(MmsVariableAccessSpecification)); + GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification)); self->domainId = domainId; self->itemId = itemId; @@ -1755,14 +1790,14 @@ void MmsVariableAccessSpecification_destroy(MmsVariableAccessSpecification* self) { if (self->domainId != NULL) - free(self->domainId); + GLOBAL_FREEMEM((void*) self->domainId); if (self->itemId != NULL) - free(self->itemId); + GLOBAL_FREEMEM((void*) self->itemId); if (self->componentName != NULL) - free(self->componentName); + GLOBAL_FREEMEM((void*) self->componentName); - free(self); + GLOBAL_FREEMEM(self); } diff --git a/src/mms/iso_mms/client/mms_client_files.c b/src/mms/iso_mms/client/mms_client_files.c index 1b46d32f..a66590e3 100644 --- a/src/mms/iso_mms/client/mms_client_files.c +++ b/src/mms/iso_mms/client/mms_client_files.c @@ -33,7 +33,7 @@ #include "conversions.h" void -mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, char* fileName, uint32_t initialPosition) +mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName, uint32_t initialPosition) { uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); @@ -66,7 +66,7 @@ mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, char* fi } void -mmsClient_createFileDeleteRequest(uint32_t invokeId, ByteBuffer* request, char* fileName) +mmsClient_createFileDeleteRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName) { uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); @@ -122,7 +122,7 @@ mmsClient_createFileReadRequest(uint32_t invokeId, ByteBuffer* request, int32_t } static int -encodeFileSpecification(uint8_t tag, char* fileSpecification, uint8_t* buffer, int bufPos) +encodeFileSpecification(uint8_t tag, const char* fileSpecification, uint8_t* buffer, int bufPos) { uint32_t fileNameStringSize = strlen(fileSpecification); uint32_t fileNameSeqSize = 1 + BerEncoder_determineLengthSize(fileNameStringSize) + fileNameStringSize; @@ -140,7 +140,7 @@ encodeFileSpecification(uint8_t tag, char* fileSpecification, uint8_t* buffer, i } void -mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, char* fileSpecification, char* continueAfter) +mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, const char* fileSpecification, const char* continueAfter) { uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); @@ -179,7 +179,7 @@ mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, cha void -mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, char* currentFileName, char* newFileName) +mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, const char* currentFileName, const char* newFileName) { uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId); @@ -314,8 +314,6 @@ parseListOfDirectoryEntries(uint8_t* buffer, int bufPos, int maxBufPos, int endPos = bufPos + length; - // printf("bufPos: %i, length: %i, maxBufPos: %i\n", bufPos, length, maxBufPos); - if (endPos > maxBufPos) { if (DEBUG_MMS_CLIENT) printf("parseListOfDirectoryEntries: message to short!\n"); diff --git a/src/mms/iso_mms/client/mms_client_get_namelist.c b/src/mms/iso_mms/client/mms_client_get_namelist.c index 4a9340e9..9332a120 100644 --- a/src/mms/iso_mms/client/mms_client_get_namelist.c +++ b/src/mms/iso_mms/client/mms_client_get_namelist.c @@ -33,7 +33,7 @@ int mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writeBuffer, - char* continueAfter) + const char* continueAfter) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -45,7 +45,7 @@ mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writ request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList); if (continueAfter != NULL) { - request->continueAfter = (Identifier_t*) calloc(1, sizeof(Identifier_t)); + request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); request->continueAfter->buf = (uint8_t*) copyString(continueAfter); request->continueAfter->size = strlen(continueAfter); } @@ -70,7 +70,7 @@ mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writ int mmsClient_createMmsGetNameListRequestAssociationSpecific(long invokeId, ByteBuffer* writeBuffer, - char* continueAfter) + const char* continueAfter) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -83,7 +83,7 @@ mmsClient_createMmsGetNameListRequestAssociationSpecific(long invokeId, ByteBuff if (continueAfter != NULL) { - request->continueAfter = (Identifier_t*) calloc(1, sizeof(Identifier_t)); + request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); request->continueAfter->buf = (uint8_t*) copyString(continueAfter); request->continueAfter->size = strlen(continueAfter); } @@ -197,8 +197,8 @@ exit_error: } int -mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, char* domainName, - ByteBuffer* writeBuffer, MmsObjectClass objectClass, char* continueAfter) +mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, const char* domainName, + ByteBuffer* writeBuffer, MmsObjectClass objectClass, const char* continueAfter) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -210,7 +210,7 @@ mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, char* domai request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList); if (continueAfter != NULL) { - request->continueAfter = (Identifier_t*) calloc(1, sizeof(Identifier_t)); + request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); request->continueAfter->buf = (uint8_t*) copyString(continueAfter); request->continueAfter->size = strlen(continueAfter); } diff --git a/src/mms/iso_mms/client/mms_client_get_var_access.c b/src/mms/iso_mms/client/mms_client_get_var_access.c index de5fb409..4e45b34e 100644 --- a/src/mms/iso_mms/client/mms_client_get_var_access.c +++ b/src/mms/iso_mms/client/mms_client_get_var_access.c @@ -33,7 +33,7 @@ static MmsVariableSpecification* createTypeSpecification(TypeSpecification_t* asnTypeSpec) { MmsVariableSpecification* typeSpec = (MmsVariableSpecification*) - calloc(1, sizeof(MmsVariableSpecification)); + GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); switch (asnTypeSpec->present) { case TypeSpecification_PR_structure: @@ -44,7 +44,7 @@ createTypeSpecification(TypeSpecification_t* asnTypeSpec) { typeSpec->typeSpec.structure.elementCount = elementCount; typeSpec->typeSpec.structure.elements = (MmsVariableSpecification**) - calloc(elementCount, sizeof(MmsVariableSpecification*)); + GLOBAL_CALLOC(elementCount, sizeof(MmsVariableSpecification*)); int i; @@ -164,7 +164,7 @@ mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t int mmsClient_createGetVariableAccessAttributesRequest( uint32_t invokeId, - char* domainId, char* itemId, + const char* domainId, const char* itemId, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); diff --git a/src/mms/iso_mms/client/mms_client_identify.c b/src/mms/iso_mms/client/mms_client_identify.c index 39f0d651..d20f2eae 100644 --- a/src/mms/iso_mms/client/mms_client_identify.c +++ b/src/mms/iso_mms/client/mms_client_identify.c @@ -101,7 +101,7 @@ mmsClient_parseIdentifyResponse(MmsConnection self) } } - identityInfo = (MmsServerIdentity*) malloc(sizeof(MmsServerIdentity)); + identityInfo = (MmsServerIdentity*) GLOBAL_MALLOC(sizeof(MmsServerIdentity)); identityInfo->vendorName = vendorName; identityInfo->modelName = modelName; diff --git a/src/mms/iso_mms/client/mms_client_initiate.c b/src/mms/iso_mms/client/mms_client_initiate.c index 544cdc67..5eed3403 100644 --- a/src/mms/iso_mms/client/mms_client_initiate.c +++ b/src/mms/iso_mms/client/mms_client_initiate.c @@ -38,18 +38,18 @@ createInitiateRequestPdu(MmsConnection self) { InitiateRequestPdu_t request; - request.localDetailCalling = (Integer32_t*) calloc(1, sizeof(Integer32_t)); + request.localDetailCalling = (Integer32_t*) GLOBAL_CALLOC(1, sizeof(Integer32_t)); *(request.localDetailCalling) = self->parameters.maxPduSize; request.proposedMaxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; request.proposedMaxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; - request.proposedDataStructureNestingLevel = (Integer8_t*) calloc(1, sizeof(Integer8_t)); + request.proposedDataStructureNestingLevel = (Integer8_t*) GLOBAL_CALLOC(1, sizeof(Integer8_t)); *(request.proposedDataStructureNestingLevel) = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL; request.mmsInitRequestDetail.proposedParameterCBB.size = 2; request.mmsInitRequestDetail.proposedParameterCBB.bits_unused = 5; - request.mmsInitRequestDetail.proposedParameterCBB.buf = (uint8_t*) calloc(2, sizeof(uint8_t)); + request.mmsInitRequestDetail.proposedParameterCBB.buf = (uint8_t*) GLOBAL_CALLOC(2, sizeof(uint8_t)); request.mmsInitRequestDetail.proposedParameterCBB.buf[0] = 0xf1; request.mmsInitRequestDetail.proposedParameterCBB.buf[1] = 0x00; @@ -66,15 +66,15 @@ createInitiateRequestPdu(MmsConnection self) static void freeInitiateRequestPdu(InitiateRequestPdu_t request) { - free(request.localDetailCalling); - free(request.proposedDataStructureNestingLevel); - free(request.mmsInitRequestDetail.proposedParameterCBB.buf); + GLOBAL_FREEMEM(request.localDetailCalling); + GLOBAL_FREEMEM(request.proposedDataStructureNestingLevel); + GLOBAL_FREEMEM(request.mmsInitRequestDetail.proposedParameterCBB.buf); } int mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message) { - MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t)); + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); mmsPdu->present = MmsPdu_PR_initiateRequestPdu; @@ -84,7 +84,7 @@ mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message) (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) message); freeInitiateRequestPdu(mmsPdu->choice.initiateRequestPdu); - free(mmsPdu); + GLOBAL_FREEMEM(mmsPdu); return rval.encoded; } diff --git a/src/mms/iso_mms/client/mms_client_named_variable_list.c b/src/mms/iso_mms/client/mms_client_named_variable_list.c index 3939bf40..161a5c70 100644 --- a/src/mms/iso_mms/client/mms_client_named_variable_list.c +++ b/src/mms/iso_mms/client/mms_client_named_variable_list.c @@ -35,7 +35,7 @@ void mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeBuffer, - char* domainId, char* listNameId) + const char* domainId, const char* listNameId) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -45,14 +45,14 @@ mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeB DeleteNamedVariableListRequest_t* request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); - request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) calloc(1, + request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1, sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName)); request->listOfVariableListName->list.count = 1; request->listOfVariableListName->list.size = 1; - request->listOfVariableListName->list.array = (ObjectName_t**) calloc(1, sizeof(ObjectName_t*)); - request->listOfVariableListName->list.array[0] = (ObjectName_t*) calloc(1, sizeof(ObjectName_t)); + request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*)); + request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t)); request->listOfVariableListName->list.array[0]->present = ObjectName_PR_domainspecific; request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.size = strlen(domainId); @@ -60,7 +60,7 @@ mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeB request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.size = strlen(listNameId); request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.buf = (uint8_t*) copyString(listNameId); - request->scopeOfDelete = (INTEGER_t*) calloc(1, sizeof(INTEGER_t)); + request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t)); asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific); der_encode(&asn_DEF_MmsPdu, mmsPdu, @@ -73,7 +73,7 @@ void mmsClient_createDeleteAssociationSpecificNamedVariableListRequest( long invokeId, ByteBuffer* writeBuffer, - char* listNameId) + const char* listNameId) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -83,21 +83,21 @@ mmsClient_createDeleteAssociationSpecificNamedVariableListRequest( DeleteNamedVariableListRequest_t* request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); - request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) calloc(1, + request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1, sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName)); request->listOfVariableListName->list.count = 1; request->listOfVariableListName->list.size = 1; - request->listOfVariableListName->list.array = (ObjectName_t**) calloc(1, sizeof(ObjectName_t*)); - request->listOfVariableListName->list.array[0] = (ObjectName_t*) calloc(1, sizeof(ObjectName_t)); + request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*)); + request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t)); request->listOfVariableListName->list.array[0]->present = ObjectName_PR_aaspecific; request->listOfVariableListName->list.array[0]->choice.aaspecific.size = strlen(listNameId); request->listOfVariableListName->list.array[0]->choice.aaspecific.buf = (uint8_t*) copyString(listNameId); - request->scopeOfDelete = (INTEGER_t*) calloc(1, sizeof(INTEGER_t)); + request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t)); asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific); der_encode(&asn_DEF_MmsPdu, mmsPdu, @@ -146,7 +146,7 @@ mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* in void mmsClient_createGetNamedVariableListAttributesRequest(uint32_t invokeId, ByteBuffer* writeBuffer, - char* domainId, char* listNameId) + const char* domainId, const char* listNameId) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -172,7 +172,7 @@ mmsClient_createGetNamedVariableListAttributesRequest(uint32_t invokeId, ByteBuf void mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(uint32_t invokeId, - ByteBuffer* writeBuffer, char* listNameId) + ByteBuffer* writeBuffer, const char* listNameId) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -257,8 +257,8 @@ void mmsClient_createDefineNamedVariableListRequest( uint32_t invokeId, ByteBuffer* writeBuffer, - char* domainId, - char* listNameId, + const char* domainId, + const char* listNameId, LinkedList /**/ listOfVariables, bool associationSpecific) { @@ -292,7 +292,7 @@ mmsClient_createDefineNamedVariableListRequest( request->listOfVariable.list.size = listSize; request->listOfVariable.list.array = - (struct DefineNamedVariableListRequest__listOfVariable__Member**) calloc(listSize, sizeof(void*)); + (struct DefineNamedVariableListRequest__listOfVariable__Member**) GLOBAL_CALLOC(listSize, sizeof(void*)); int i = 0; LinkedList element = LinkedList_getNext(listOfVariables); @@ -301,7 +301,7 @@ mmsClient_createDefineNamedVariableListRequest( MmsVariableAccessSpecification* variableSpec = (MmsVariableAccessSpecification*) element->data; request->listOfVariable.list.array[i] = (struct DefineNamedVariableListRequest__listOfVariable__Member*) - calloc(1, sizeof(struct DefineNamedVariableListRequest__listOfVariable__Member)); + GLOBAL_CALLOC(1, sizeof(struct DefineNamedVariableListRequest__listOfVariable__Member)); request->listOfVariable.list.array[i]->variableSpecification.present = VariableSpecification_PR_name; @@ -324,13 +324,13 @@ mmsClient_createDefineNamedVariableListRequest( //TODO add alternate access if (variableSpec->arrayIndex != -1) { - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) calloc(1, sizeof(AlternateAccess_t)); + AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) calloc(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) calloc(1, sizeof(struct AlternateAccess__Member)); + alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); + alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) calloc(1, sizeof(AlternateAccessSelection_t)); + alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; @@ -343,14 +343,14 @@ mmsClient_createDefineNamedVariableListRequest( if (variableSpec->componentName != NULL) { - AlternateAccess_t* componentAccess = (AlternateAccess_t*) calloc(1, sizeof(AlternateAccess_t)); + AlternateAccess_t* componentAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); componentAccess->list.count = 1; - componentAccess->list.array = (struct AlternateAccess__Member**) calloc(1, sizeof(struct AlternateAccess__Member*)); - componentAccess->list.array[0] = (struct AlternateAccess__Member*) calloc(1, sizeof(struct AlternateAccess__Member)); + componentAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); + componentAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); componentAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - componentAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) calloc(1, sizeof(AlternateAccessSelection_t)); + componentAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); componentAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c index f860269d..5c39235e 100644 --- a/src/mms/iso_mms/client/mms_client_read.c +++ b/src/mms/iso_mms/client/mms_client_read.c @@ -67,14 +67,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); } else if (presentType == AccessResult_PR_array) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_ARRAY; int arrayElementCount = accessResultList[i]->choice.array.list.count; value->value.structure.size = arrayElementCount; - value->value.structure.components = (MmsValue**) calloc(arrayElementCount, sizeof(MmsValue*)); + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); int j; @@ -84,14 +84,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi } } else if (presentType == AccessResult_PR_structure) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_STRUCTURE; int componentCount = accessResultList[i]->choice.structure.list.count; value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int j; for (j = 0; j < componentCount; j++) { @@ -100,14 +100,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi } } else if (presentType == AccessResult_PR_bitstring) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BIT_STRING; int size = accessResultList[i]->choice.bitstring.size; value->value.bitString.size = (size * 8) - accessResultList[i]->choice.bitstring.bits_unused; - value->value.bitString.buf = (uint8_t*) malloc(size); + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.bitString.buf, accessResultList[i]->choice.bitstring.buf, size); @@ -129,7 +129,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi else if (presentType == AccessResult_PR_floatingpoint) { int size = accessResultList[i]->choice.floatingpoint.size; - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_FLOAT; if (size == 5) { /* FLOAT32 */ @@ -138,7 +138,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); - value->value.floatingPoint.buf = (uint8_t*) malloc(4); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); @@ -154,7 +154,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); - value->value.floatingPoint.buf = (uint8_t*) malloc(8); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); @@ -165,13 +165,13 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi } else if (presentType == AccessResult_PR_visiblestring) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_VISIBLE_STRING; int strSize = accessResultList[i]->choice.visiblestring.size; - value->value.visibleString.buf = (char*) malloc(strSize + 1); + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); value->value.visibleString.size = strSize; memcpy(value->value.visibleString.buf, @@ -181,13 +181,13 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi value->value.visibleString.buf[strSize] = 0; } else if (presentType == AccessResult_PR_mMSString) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_STRING; int strSize = accessResultList[i]->choice.mMSString.size; - value->value.visibleString.buf = (char*) malloc(strSize + 1); + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); value->value.visibleString.size = strSize; memcpy(value->value.visibleString.buf, @@ -197,7 +197,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi } else if (presentType == AccessResult_PR_utctime) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; memcpy(value->value.utcTime, @@ -210,7 +210,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi int size = accessResultList[i]->choice.binarytime.size; if (size <= 6) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; value->value.binaryTime.size = size; memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); @@ -219,11 +219,11 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi else if (presentType == AccessResult_PR_octetstring) { int size = accessResultList[i]->choice.octetstring.size; - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; value->value.octetString.maxSize = size; value->value.octetString.size = size; - value->value.octetString.buf = (uint8_t*) malloc(size); + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); } else { @@ -291,7 +291,7 @@ createReadRequest (MmsPdu_t* mmsPdu) int -mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, char* domainId, char* itemId, +mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, const char* domainId, const char* itemId, ByteBuffer* writeBuffer, bool specWithResult) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -330,7 +330,7 @@ mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, char* domainId, int mmsClient_createReadAssociationSpecificNamedVariableListRequest( uint32_t invokeId, - char* itemId, + const char* itemId, ByteBuffer* writeBuffer, bool specWithResult) { @@ -368,7 +368,7 @@ mmsClient_createReadAssociationSpecificNamedVariableListRequest( * Request a single value */ int -mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, ByteBuffer* writeBuffer) +mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* itemId, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -379,10 +379,10 @@ mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, Byt readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; readRequest->variableAccessSpecification.choice.listOfVariable.list.array = - (ListOfVariableSeq_t**) calloc(1, sizeof(ListOfVariableSeq_t*)); + (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1; - ListOfVariableSeq_t* listOfVars = (ListOfVariableSeq_t*) calloc(1, sizeof(ListOfVariableSeq_t)); + ListOfVariableSeq_t* listOfVars = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = listOfVars; @@ -408,8 +408,8 @@ mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, Byt (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); /* clean up data structures */ - free(listOfVars); - free(readRequest->variableAccessSpecification.choice.listOfVariable.list.array); + GLOBAL_FREEMEM(listOfVars); + GLOBAL_FREEMEM(readRequest->variableAccessSpecification.choice.listOfVariable.list.array); readRequest->variableAccessSpecification.choice.listOfVariable.list.array = NULL; readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0; asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); @@ -420,13 +420,13 @@ mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, Byt static AlternateAccess_t* createAlternateAccess(uint32_t index, uint32_t elementCount) { - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) calloc(1, sizeof(AlternateAccess_t)); + AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) calloc(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) calloc(1, sizeof(struct AlternateAccess__Member)); + alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); + alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) calloc(1, sizeof(AlternateAccessSelection_t)); + alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; @@ -458,9 +458,9 @@ createAlternateAccess(uint32_t index, uint32_t elementCount) } static ListOfVariableSeq_t* -createVariableIdentifier(char* domainId, char* itemId) +createVariableIdentifier(const char* domainId, const char* itemId) { - ListOfVariableSeq_t* variableIdentifier = (ListOfVariableSeq_t*) calloc(1, sizeof(ListOfVariableSeq_t)); + ListOfVariableSeq_t* variableIdentifier = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); variableIdentifier->variableSpecification.present = VariableSpecification_PR_name; variableIdentifier->variableSpecification.choice.name.present = ObjectName_PR_domainspecific; @@ -473,7 +473,7 @@ createVariableIdentifier(char* domainId, char* itemId) } int -mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, char* domainId, char* itemId, +mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* domainId, const char* itemId, uint32_t index, uint32_t elementCount, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -483,7 +483,7 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, char* domainI readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; - readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) calloc(1, sizeof(ListOfVariableSeq_t*)); + readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1; ListOfVariableSeq_t* variableIdentifier = createVariableIdentifier(domainId, itemId); @@ -512,7 +512,7 @@ createListOfVariables(ReadRequest_t* readRequest, int valuesCount) { readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) - calloc(valuesCount, sizeof(ListOfVariableSeq_t*)); + GLOBAL_CALLOC(valuesCount, sizeof(ListOfVariableSeq_t*)); readRequest->variableAccessSpecification.choice.listOfVariable.list.count = valuesCount; readRequest->variableAccessSpecification.choice.listOfVariable.list.size = valuesCount; @@ -523,7 +523,7 @@ createListOfVariables(ReadRequest_t* readRequest, int valuesCount) { * Request multiple values of a single domain */ int -mmsClient_createReadRequestMultipleValues(uint32_t invokeId, char* domainId, LinkedList items, +mmsClient_createReadRequestMultipleValues(uint32_t invokeId, const char* domainId, LinkedList items, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -551,9 +551,9 @@ mmsClient_createReadRequestMultipleValues(uint32_t invokeId, char* domainId, Lin (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); for (i = 0; i < valuesCount; i++) { - free(listOfVars[i]); + GLOBAL_FREEMEM(listOfVars[i]); } - free(listOfVars); + GLOBAL_FREEMEM(listOfVars); readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0; readRequest->variableAccessSpecification.choice.listOfVariable.list.size = 0; diff --git a/src/mms/iso_mms/client/mms_client_write.c b/src/mms/iso_mms/client/mms_client_write.c index 623461f8..5657ef45 100644 --- a/src/mms/iso_mms/client/mms_client_write.c +++ b/src/mms/iso_mms/client/mms_client_write.c @@ -172,9 +172,9 @@ mmsClient_parseWriteResponse(ByteBuffer* message, int32_t bufPos, MmsError* mmsE } static VariableSpecification_t* -createNewDomainVariableSpecification(char* domainId, char* itemId) +createNewDomainVariableSpecification(const char* domainId, const char* itemId) { - VariableSpecification_t* varSpec = (VariableSpecification_t*) calloc(1, sizeof(ListOfVariableSeq_t)); + VariableSpecification_t* varSpec = (VariableSpecification_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t)); //VariableSpecification_t* varSpec = (VariableSpecification_t*) calloc(1, sizeof(VariableSpecification_t)); @@ -204,8 +204,8 @@ deleteDataElement(Data_t* dataElement) deleteDataElement(dataElement->choice.structure->list.array[i]); } - free(dataElement->choice.structure->list.array); - free(dataElement->choice.structure); + GLOBAL_FREEMEM(dataElement->choice.structure->list.array); + GLOBAL_FREEMEM(dataElement->choice.structure); } else if (dataElement->present == Data_PR_array) { int elementCount = dataElement->choice.array->list.count; @@ -215,21 +215,21 @@ deleteDataElement(Data_t* dataElement) deleteDataElement(dataElement->choice.array->list.array[i]); } - free(dataElement->choice.array->list.array); - free(dataElement->choice.array); + GLOBAL_FREEMEM(dataElement->choice.array->list.array); + GLOBAL_FREEMEM(dataElement->choice.array); } else if (dataElement->present == Data_PR_floatingpoint) { - free(dataElement->choice.floatingpoint.buf); + GLOBAL_FREEMEM(dataElement->choice.floatingpoint.buf); } else if (dataElement->present == Data_PR_utctime) { - free(dataElement->choice.utctime.buf); + GLOBAL_FREEMEM(dataElement->choice.utctime.buf); } - free(dataElement); + GLOBAL_FREEMEM(dataElement); } int -mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, LinkedList itemIds, LinkedList values, +mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, const char* domainId, LinkedList itemIds, LinkedList values, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -246,12 +246,12 @@ mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, Lin request->variableAccessSpecification.choice.listOfVariable.list.count = numberOfItems; request->variableAccessSpecification.choice.listOfVariable.list.size = numberOfItems; request->variableAccessSpecification.choice.listOfVariable.list.array = - (ListOfVariableSeq_t**) calloc(numberOfItems, sizeof(ListOfVariableSeq_t*)); + (ListOfVariableSeq_t**) GLOBAL_CALLOC(numberOfItems, sizeof(ListOfVariableSeq_t*)); /* Create list of data values */ request->listOfData.list.count = numberOfItems; request->listOfData.list.size = numberOfItems; - request->listOfData.list.array = (Data_t**) calloc(numberOfItems, sizeof(struct Data*)); + request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(numberOfItems, sizeof(struct Data*)); int i; @@ -283,16 +283,16 @@ mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, Lin request->variableAccessSpecification.choice.listOfVariable.list.count = 0; for (i = 0; i < numberOfItems; i++) { - free(request->variableAccessSpecification.choice.listOfVariable.list.array[i]); + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[i]); deleteDataElement(request->listOfData.list.array[i]); } - free(request->variableAccessSpecification.choice.listOfVariable.list.array); + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array); request->variableAccessSpecification.choice.listOfVariable.list.array = 0; request->listOfData.list.count = 0; - free(request->listOfData.list.array); + GLOBAL_FREEMEM(request->listOfData.list.array); request->listOfData.list.array = 0; asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); @@ -302,7 +302,7 @@ mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, Lin } int -mmsClient_createWriteRequest(uint32_t invokeId, char* domainId, char* itemId, MmsValue* value, +mmsClient_createWriteRequest(uint32_t invokeId, const char* domainId, const char* itemId, MmsValue* value, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); @@ -317,14 +317,14 @@ mmsClient_createWriteRequest(uint32_t invokeId, char* domainId, char* itemId, Mm request->variableAccessSpecification.choice.listOfVariable.list.count = 1; request->variableAccessSpecification.choice.listOfVariable.list.size = 1; request->variableAccessSpecification.choice.listOfVariable.list.array = - (ListOfVariableSeq_t**) calloc(1, sizeof(ListOfVariableSeq_t*)); + (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); request->variableAccessSpecification.choice.listOfVariable.list.array[0] = (ListOfVariableSeq_t*) createNewDomainVariableSpecification(domainId, itemId); /* Create list of typed data values */ request->listOfData.list.count = 1; request->listOfData.list.size = 1; - request->listOfData.list.array = (Data_t**) calloc(1, sizeof(struct Data*)); + request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(1, sizeof(struct Data*)); request->listOfData.list.array[0] = mmsMsg_createBasicDataElement(value); asn_enc_rval_t rval; @@ -335,15 +335,15 @@ mmsClient_createWriteRequest(uint32_t invokeId, char* domainId, char* itemId, Mm /* Free ASN structure */ request->variableAccessSpecification.choice.listOfVariable.list.count = 0; - free(request->variableAccessSpecification.choice.listOfVariable.list.array[0]); - free(request->variableAccessSpecification.choice.listOfVariable.list.array); + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[0]); + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array); request->variableAccessSpecification.choice.listOfVariable.list.array = 0; request->listOfData.list.count = 0; deleteDataElement(request->listOfData.list.array[0]); - free(request->listOfData.list.array); + GLOBAL_FREEMEM(request->listOfData.list.array); request->listOfData.list.array = 0; asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c index 019705c5..6b2e07c5 100644 --- a/src/mms/iso_mms/common/mms_common_msg.c +++ b/src/mms/iso_mms/common/mms_common_msg.c @@ -33,7 +33,7 @@ mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf) { if (value->value.floatingPoint.formatWidth == 64) { *size = 9; - *buf = (uint8_t*) malloc(9); + *buf = (uint8_t*) GLOBAL_MALLOC(9); (*buf)[0] = 11; #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder((*buf) + 1, value->value.floatingPoint.buf, 8); @@ -42,7 +42,7 @@ mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf) #endif } else { *size = 5; - *buf = (uint8_t*) malloc(5); + *buf = (uint8_t*) GLOBAL_MALLOC(5); (*buf)[0] = 8; #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder((*buf) + 1, value->value.floatingPoint.buf, 4); @@ -55,17 +55,17 @@ mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf) Data_t* mmsMsg_createBasicDataElement(MmsValue* value) { - Data_t* dataElement = (Data_t*) calloc(1, sizeof(Data_t)); + Data_t* dataElement = (Data_t*) GLOBAL_CALLOC(1, sizeof(Data_t)); switch (value->type) { case MMS_ARRAY: { int size = MmsValue_getArraySize(value); dataElement->present = Data_PR_array; - dataElement->choice.array = (DataSequence_t*) calloc(1, sizeof(DataSequence_t)); + dataElement->choice.array = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t)); dataElement->choice.array->list.count = size; dataElement->choice.array->list.size = size; - dataElement->choice.array->list.array = (Data_t**) calloc(size, sizeof(Data_t*)); + dataElement->choice.array->list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*)); int i; for (i = 0; i < size; i++) { dataElement->choice.array->list.array[i] = @@ -79,10 +79,10 @@ mmsMsg_createBasicDataElement(MmsValue* value) int size = value->value.structure.size; dataElement->present = Data_PR_structure; - dataElement->choice.structure = (DataSequence_t*) calloc(1, sizeof(DataSequence_t)); + dataElement->choice.structure = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t)); dataElement->choice.structure->list.count = size; dataElement->choice.structure->list.size = size; - dataElement->choice.structure->list.array = (Data_t**) calloc(size, sizeof(Data_t*)); + dataElement->choice.structure->list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*)); int i; for (i = 0; i < size; i++) { dataElement->choice.structure->list.array[i] = mmsMsg_createBasicDataElement( @@ -117,7 +117,7 @@ mmsMsg_createBasicDataElement(MmsValue* value) case MMS_UTC_TIME: dataElement->present = Data_PR_utctime; - dataElement->choice.utctime.buf = (uint8_t*) malloc(8); + dataElement->choice.utctime.buf = (uint8_t*) GLOBAL_MALLOC(8); memcpy(dataElement->choice.utctime.buf, value->value.utcTime, 8); dataElement->choice.utctime.size = 8; break; @@ -174,7 +174,7 @@ mmsMsg_createBasicDataElement(MmsValue* value) default: dataElement->present = Data_PR_NOTHING; - printf("MMS read: unknown value type %i in result\n", value->type); + break; } @@ -187,13 +187,13 @@ mmsMsg_parseDataElement(Data_t* dataElement) MmsValue* value = NULL; if (dataElement->present == Data_PR_structure) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int componentCount = dataElement->choice.structure->list.count; value->type = MMS_STRUCTURE; value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; @@ -203,13 +203,13 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } else if (dataElement->present == Data_PR_array) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int componentCount = dataElement->choice.array->list.count; value->type = MMS_ARRAY; value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; @@ -240,7 +240,7 @@ mmsMsg_parseDataElement(Data_t* dataElement) dataElement->choice.mMSString.size); } else if (dataElement->present == Data_PR_bitstring) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BIT_STRING; int size = dataElement->choice.bitstring.size; @@ -248,13 +248,13 @@ mmsMsg_parseDataElement(Data_t* dataElement) value->value.bitString.size = (size * 8) - dataElement->choice.bitstring.bits_unused; - value->value.bitString.buf = (uint8_t*) malloc(size); + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.bitString.buf, dataElement->choice.bitstring.buf, size); } else if (dataElement->present == Data_PR_floatingpoint) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int size = dataElement->choice.floatingpoint.size; value->type = MMS_FLOAT; @@ -265,7 +265,7 @@ mmsMsg_parseDataElement(Data_t* dataElement) uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); - value->value.floatingPoint.buf = (uint8_t*) malloc(4); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); #else @@ -279,7 +279,7 @@ mmsMsg_parseDataElement(Data_t* dataElement) uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); - value->value.floatingPoint.buf = (uint8_t*) malloc(8); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); #else @@ -288,24 +288,24 @@ mmsMsg_parseDataElement(Data_t* dataElement) } } else if (dataElement->present == Data_PR_utctime) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); } else if (dataElement->present == Data_PR_octetstring) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; int size = dataElement->choice.octetstring.size; value->value.octetString.size = size; value->value.octetString.maxSize = size; - value->value.octetString.buf = (uint8_t*) malloc(size); + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); } else if (dataElement->present == Data_PR_binarytime) { int size = dataElement->choice.binarytime.size; if (size <= 6) { - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; value->value.binaryTime.size = size; memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size); @@ -324,18 +324,18 @@ Data_t* mmsMsg_createDataElement(MmsValue* value) { if (value->type == MMS_STRUCTURE) { - Data_t* dataElement = (Data_t*) calloc(1, sizeof(Data_t)); + Data_t* dataElement = (Data_t*) GLOBAL_CALLOC(1, sizeof(Data_t)); dataElement->present = Data_PR_structure; int elementCount = value->value.structure.size; - dataElement->choice.structure = (DataSequence_t*) calloc(1, sizeof(DataSequence_t)); + dataElement->choice.structure = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t)); dataElement->choice.structure->list.size = elementCount; dataElement->choice.structure->list.count = elementCount; - dataElement->choice.structure->list.array = (Data_t**) calloc(elementCount, sizeof(Data_t*)); + dataElement->choice.structure->list.array = (Data_t**) GLOBAL_CALLOC(elementCount, sizeof(Data_t*)); int i; @@ -370,7 +370,7 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value) accessResult->present = AccessResult_PR_array; accessResult->choice.array.list.count = size; accessResult->choice.array.list.size = size; - accessResult->choice.array.list.array = (Data_t**) calloc(size, sizeof(Data_t*)); + accessResult->choice.array.list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*)); int i; for (i = 0; i < size; i++) { accessResult->choice.array.list.array[i] = @@ -384,7 +384,7 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value) accessResult->present = AccessResult_PR_structure; accessResult->choice.structure.list.count = size; accessResult->choice.structure.list.size = size; - accessResult->choice.structure.list.array = (Data_t**) calloc(size, sizeof(Data_t*)); + accessResult->choice.structure.list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*)); int i; for (i = 0; i < size; i++) { accessResult->choice.structure.list.array[i] = @@ -416,7 +416,7 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value) break; case MMS_UTC_TIME: accessResult->present = AccessResult_PR_utctime; - accessResult->choice.utctime.buf = (uint8_t*) malloc(8); + accessResult->choice.utctime.buf = (uint8_t*) GLOBAL_MALLOC(8); memcpy(accessResult->choice.utctime.buf, value->value.utcTime, 8); accessResult->choice.utctime.size = 8; break; @@ -470,8 +470,8 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value) asn_long2INTEGER(&accessResult->choice.failure, DataAccessError_typeinconsistent); - if (1) - printf("MMS read: unknown value type %i in result\n", value->type); + + break; } } @@ -485,12 +485,12 @@ mmsMsg_createAccessResultsList(MmsPdu_t* mmsPdu, int resultsCount) readResponse->listOfAccessResult.list.size = resultsCount; readResponse->listOfAccessResult.list.count = resultsCount; - readResponse->listOfAccessResult.list.array = (AccessResult_t**) calloc(resultsCount, sizeof(AccessResult_t*)); + readResponse->listOfAccessResult.list.array = (AccessResult_t**) GLOBAL_CALLOC(resultsCount, sizeof(AccessResult_t*)); int i; for (i = 0; i < resultsCount; i++) { - readResponse->listOfAccessResult.list.array[i] = (AccessResult_t*) calloc(1, sizeof(AccessResult_t)); + readResponse->listOfAccessResult.list.array[i] = (AccessResult_t*) GLOBAL_CALLOC(1, sizeof(AccessResult_t)); } AccessResult_t** accessResultList = readResponse->listOfAccessResult.list.array; @@ -514,8 +514,8 @@ deleteDataElement(Data_t* dataElement) deleteDataElement(dataElement->choice.structure->list.array[i]); } - free(dataElement->choice.structure->list.array); - free(dataElement->choice.structure); + GLOBAL_FREEMEM(dataElement->choice.structure->list.array); + GLOBAL_FREEMEM(dataElement->choice.structure); } else if (dataElement->present == Data_PR_array) { int elementCount = dataElement->choice.array->list.count; @@ -525,17 +525,17 @@ deleteDataElement(Data_t* dataElement) deleteDataElement(dataElement->choice.array->list.array[i]); } - free(dataElement->choice.array->list.array); - free(dataElement->choice.array); + GLOBAL_FREEMEM(dataElement->choice.array->list.array); + GLOBAL_FREEMEM(dataElement->choice.array); } else if (dataElement->present == Data_PR_floatingpoint) { - free(dataElement->choice.floatingpoint.buf); + GLOBAL_FREEMEM(dataElement->choice.floatingpoint.buf); } else if (dataElement->present == Data_PR_utctime) { - free(dataElement->choice.utctime.buf); + GLOBAL_FREEMEM(dataElement->choice.utctime.buf); } - free(dataElement); + GLOBAL_FREEMEM(dataElement); } void @@ -554,7 +554,7 @@ mmsMsg_deleteAccessResultList(AccessResult_t** accessResult, int variableCount) deleteDataElement(accessResult[i]->choice.structure.list.array[j]); } - free(accessResult[i]->choice.structure.list.array); + GLOBAL_FREEMEM(accessResult[i]->choice.structure.list.array); } else if (accessResult[i]->present == AccessResult_PR_array) { int elementCount = accessResult[i]->choice.array.list.count; @@ -565,23 +565,23 @@ mmsMsg_deleteAccessResultList(AccessResult_t** accessResult, int variableCount) deleteDataElement(accessResult[i]->choice.array.list.array[j]); } - free(accessResult[i]->choice.array.list.array); + GLOBAL_FREEMEM(accessResult[i]->choice.array.list.array); } else if (accessResult[i]->present == AccessResult_PR_integer) - free(accessResult[i]->choice.integer.buf); + GLOBAL_FREEMEM(accessResult[i]->choice.integer.buf); else if (accessResult[i]->present == AccessResult_PR_unsigned) - free(accessResult[i]->choice.Unsigned.buf); + GLOBAL_FREEMEM(accessResult[i]->choice.Unsigned.buf); else if (accessResult[i]->present == AccessResult_PR_floatingpoint) - free(accessResult[i]->choice.floatingpoint.buf); + GLOBAL_FREEMEM(accessResult[i]->choice.floatingpoint.buf); else if (accessResult[i]->present == AccessResult_PR_utctime) - free(accessResult[i]->choice.utctime.buf); + GLOBAL_FREEMEM(accessResult[i]->choice.utctime.buf); else if (accessResult[i]->present == AccessResult_PR_failure) - free(accessResult[i]->choice.failure.buf); + GLOBAL_FREEMEM(accessResult[i]->choice.failure.buf); - free(accessResult[i]); + GLOBAL_FREEMEM(accessResult[i]); } - free(accessResult); + GLOBAL_FREEMEM(accessResult); } diff --git a/src/mms/iso_mms/common/mms_type_spec.c b/src/mms/iso_mms/common/mms_type_spec.c index b4ce3a04..e88e70d5 100644 --- a/src/mms/iso_mms/common/mms_type_spec.c +++ b/src/mms/iso_mms/common/mms_type_spec.c @@ -30,7 +30,7 @@ void MmsVariableSpecification_destroy(MmsVariableSpecification* typeSpec) { if (typeSpec->name != NULL) - free(typeSpec->name); + GLOBAL_FREEMEM(typeSpec->name); if (typeSpec->type == MMS_STRUCTURE) { int elementCount = typeSpec->typeSpec.structure.elementCount; @@ -39,17 +39,17 @@ MmsVariableSpecification_destroy(MmsVariableSpecification* typeSpec) MmsVariableSpecification_destroy(typeSpec->typeSpec.structure.elements[i]); } - free(typeSpec->typeSpec.structure.elements); + GLOBAL_FREEMEM(typeSpec->typeSpec.structure.elements); } else if (typeSpec->type == MMS_ARRAY) { MmsVariableSpecification_destroy(typeSpec->typeSpec.array.elementTypeSpec); } - free(typeSpec); + GLOBAL_FREEMEM(typeSpec); } static size_t -directChildStrLen(char* childId) +directChildStrLen(const char* childId) { size_t i = 0; size_t childIdLen = strlen(childId); @@ -63,7 +63,7 @@ directChildStrLen(char* childId) } MmsValue* -MmsVariableSpecification_getChildValue(MmsVariableSpecification* typeSpec, MmsValue* value, char* childId) +MmsVariableSpecification_getChildValue(MmsVariableSpecification* typeSpec, MmsValue* value, const char* childId) { if (typeSpec->type == MMS_STRUCTURE) { size_t childLen = directChildStrLen(childId); @@ -95,7 +95,7 @@ MmsVariableSpecification_getType(MmsVariableSpecification* self) return self->type; } -char* +const char* MmsVariableSpecification_getName(MmsVariableSpecification* self) { return self->name; @@ -120,9 +120,9 @@ MmsVariableSpecification_getStructureElements(MmsVariableSpecification* self) } MmsVariableSpecification* -MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* variable, char* nameId) +MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* variable, const char* nameId) { - char* separator = strchr(nameId, '$'); + const char* separator = strchr(nameId, '$'); int i; diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c index bf753eae..0fc58d29 100644 --- a/src/mms/iso_mms/common/mms_value.c +++ b/src/mms/iso_mms/common/mms_value.c @@ -70,7 +70,7 @@ updateStructuredComponent(MmsValue* self, MmsValue* update) MmsValue* MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); self->type = MMS_INTEGER; self->value.integer = berInteger; @@ -81,7 +81,7 @@ MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger) MmsValue* MmsValue_newUnsignedFromBerInteger(Asn1PrimitiveValue* berInteger) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); self->type = MMS_UNSIGNED; self->value.integer = berInteger; @@ -281,7 +281,7 @@ MmsValue_update(MmsValue* self, MmsValue* update) MmsValue* MmsValue_newDataAccessError(MmsDataAccessError accessError) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); self->type = MMS_DATA_ACCESS_ERROR; self->value.dataAccessError = accessError; @@ -292,11 +292,11 @@ MmsValue_newDataAccessError(MmsDataAccessError accessError) MmsValue* MmsValue_newBitString(int bitSize) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));; + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; self->type = MMS_BIT_STRING; self->value.bitString.size = bitSize; - self->value.bitString.buf = (uint8_t*) calloc(bitStringByteSize(self), 1); + self->value.bitString.buf = (uint8_t*) GLOBAL_CALLOC(bitStringByteSize(self), 1); return self; } @@ -441,16 +441,47 @@ MmsValue_setBitStringFromInteger(MmsValue* self, uint32_t intValue) } } +uint32_t +MmsValue_getBitStringAsIntegerBigEndian(MmsValue* self) +{ + uint32_t value = 0; + + int bitPos; + + for (bitPos = (self->value.bitString.size - 1); bitPos >= 0; bitPos--) { + if (MmsValue_getBitStringBit(self, bitPos)) { + value += (1 << bitPos); + } + } + + return value; +} + +void +MmsValue_setBitStringFromIntegerBigEndian(MmsValue* self, uint32_t intValue) +{ + int bitPos; + + for (bitPos = (self->value.bitString.size - 1); bitPos >= 0; bitPos--) { + if ((intValue & 1) == 1) + MmsValue_setBitStringBit(self, bitPos, true); + else + MmsValue_setBitStringBit(self, bitPos, false); + + intValue = intValue >> 1; + } +} + MmsValue* MmsValue_newFloat(float variable) { - MmsValue* value = (MmsValue*) malloc(sizeof(MmsValue));; + MmsValue* value = (MmsValue*) GLOBAL_MALLOC(sizeof(MmsValue));; value->type = MMS_FLOAT; value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = 8; - value->value.floatingPoint.buf = (uint8_t*) malloc(4); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); *((float*) value->value.floatingPoint.buf) = variable; @@ -486,12 +517,12 @@ MmsValue_setDouble(MmsValue* value, double newFloatValue) MmsValue* MmsValue_newDouble(double variable) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_FLOAT; value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.exponentWidth = 11; - value->value.floatingPoint.buf = (uint8_t*) malloc(8); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); *((double*) value->value.floatingPoint.buf) = variable; @@ -501,7 +532,7 @@ MmsValue_newDouble(double variable) MmsValue* MmsValue_newIntegerFromInt8(int8_t integer) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt32((int32_t) integer); @@ -512,7 +543,7 @@ MmsValue_newIntegerFromInt8(int8_t integer) MmsValue* MmsValue_newIntegerFromInt16(int16_t integer) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt32((int32_t) integer); @@ -704,7 +735,7 @@ MmsValue_getUtcTimeInMs(MmsValue* self) MmsValue* MmsValue_newIntegerFromInt32(int32_t integer) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt32(integer); @@ -715,7 +746,7 @@ MmsValue_newIntegerFromInt32(int32_t integer) MmsValue* MmsValue_newUnsignedFromUint32(uint32_t integer) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; value->type = MMS_UNSIGNED; value->value.integer = BerInteger_createFromUint32(integer); @@ -726,7 +757,7 @@ MmsValue_newUnsignedFromUint32(uint32_t integer) MmsValue* MmsValue_newIntegerFromInt64(int64_t integer) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));; value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt64(integer); @@ -949,7 +980,7 @@ MmsValue_cloneToBuffer(MmsValue* self, uint8_t* destinationAddress) MmsValue* MmsValue_clone(MmsValue* value) { - MmsValue* newValue = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); newValue->deleteValue = value->deleteValue; newValue->type = value->type; int size; @@ -961,7 +992,7 @@ MmsValue_clone(MmsValue* value) { int componentCount = value->value.structure.size; newValue->value.structure.size = componentCount; - newValue->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); + newValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; for (i = 0; i < componentCount; i++) { newValue->value.structure.components[i] = @@ -978,13 +1009,13 @@ MmsValue_clone(MmsValue* value) newValue->value.floatingPoint.formatWidth = value->value.floatingPoint.formatWidth; newValue->value.floatingPoint.exponentWidth = value->value.floatingPoint.exponentWidth; size = value->value.floatingPoint.formatWidth / 8; - newValue->value.floatingPoint.buf = (uint8_t*) malloc(size); + newValue->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(newValue->value.floatingPoint.buf, value->value.floatingPoint.buf, size); break; case MMS_BIT_STRING: newValue->value.bitString.size = value->value.bitString.size; size = bitStringByteSize(value); - newValue->value.bitString.buf = (uint8_t*) malloc(size); + newValue->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(newValue->value.bitString.buf, value->value.bitString.buf, size); break; case MMS_BOOLEAN: @@ -994,7 +1025,7 @@ MmsValue_clone(MmsValue* value) size = value->value.octetString.size; newValue->value.octetString.size = size; newValue->value.octetString.maxSize = value->value.octetString.maxSize; - newValue->value.octetString.buf = (uint8_t*) malloc(value->value.octetString.maxSize); + newValue->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(value->value.octetString.maxSize); memcpy(newValue->value.octetString.buf, value->value.octetString.buf, size); break; case MMS_UTC_TIME: @@ -1007,7 +1038,7 @@ MmsValue_clone(MmsValue* value) case MMS_VISIBLE_STRING: case MMS_STRING: size = value->value.visibleString.size; - newValue->value.visibleString.buf = (char*) malloc(size + 1); + newValue->value.visibleString.buf = (char*) GLOBAL_MALLOC(size + 1); newValue->value.visibleString.size = size; strcpy(newValue->value.visibleString.buf, value->value.visibleString.buf); break; @@ -1043,18 +1074,18 @@ MmsValue_delete(MmsValue* value) Asn1PrimitiveValue_destroy(value->value.integer); break; case MMS_FLOAT: - free(value->value.floatingPoint.buf); + GLOBAL_FREEMEM(value->value.floatingPoint.buf); break; case MMS_BIT_STRING: - free(value->value.bitString.buf); + GLOBAL_FREEMEM(value->value.bitString.buf); break; case MMS_OCTET_STRING: - free(value->value.octetString.buf); + GLOBAL_FREEMEM(value->value.octetString.buf); break; case MMS_VISIBLE_STRING: case MMS_STRING: if (value->value.visibleString.buf != NULL) - free(value->value.visibleString.buf); + GLOBAL_FREEMEM(value->value.visibleString.buf); break; case MMS_ARRAY: case MMS_STRUCTURE: @@ -1067,13 +1098,13 @@ MmsValue_delete(MmsValue* value) MmsValue_delete(value->value.structure.components[i]); } } - free(value->value.structure.components); + GLOBAL_FREEMEM(value->value.structure.components); break; default: break; } - free(value); + GLOBAL_FREEMEM(value); } /* delete only when deleteValue field set */ @@ -1088,18 +1119,18 @@ MmsValue_deleteConditional(MmsValue* value) Asn1PrimitiveValue_destroy(value->value.integer); break; case MMS_FLOAT: - free(value->value.floatingPoint.buf); + GLOBAL_FREEMEM(value->value.floatingPoint.buf); break; case MMS_BIT_STRING: - free(value->value.bitString.buf); + GLOBAL_FREEMEM(value->value.bitString.buf); break; case MMS_OCTET_STRING: - free(value->value.octetString.buf); + GLOBAL_FREEMEM(value->value.octetString.buf); break; case MMS_VISIBLE_STRING: case MMS_STRING: if (value->value.visibleString.buf != NULL) - free(value->value.visibleString.buf); + GLOBAL_FREEMEM(value->value.visibleString.buf); break; case MMS_ARRAY: case MMS_STRUCTURE: @@ -1112,20 +1143,20 @@ MmsValue_deleteConditional(MmsValue* value) MmsValue_deleteConditional(value->value.structure.components[i]); } } - free(value->value.structure.components); + GLOBAL_FREEMEM(value->value.structure.components); break; default: break; } - free(value); + GLOBAL_FREEMEM(value); } } MmsValue* MmsValue_newInteger(int size /*integer size in bits*/) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_INTEGER; if (size <= 32) @@ -1139,7 +1170,7 @@ MmsValue_newInteger(int size /*integer size in bits*/) MmsValue* MmsValue_newUnsigned(int size /*integer size in bits*/) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UNSIGNED; if (size <= 32) @@ -1153,7 +1184,7 @@ MmsValue_newUnsigned(int size /*integer size in bits*/) MmsValue* MmsValue_newBoolean(bool boolean) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); self->type = MMS_BOOLEAN; if (boolean == true) self->value.boolean = 1; @@ -1166,11 +1197,11 @@ MmsValue_newBoolean(bool boolean) MmsValue* MmsValue_newOctetString(int size, int maxSize) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); self->type = MMS_OCTET_STRING; self->value.octetString.size = size; self->value.octetString.maxSize = maxSize; - self->value.octetString.buf = (uint8_t*) calloc(1, maxSize); + self->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, maxSize); return self; } @@ -1205,12 +1236,12 @@ MmsValue_getOctetStringBuffer(MmsValue* self) MmsValue* MmsValue_newStructure(MmsVariableSpecification* typeSpec) { - MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); self->type = MMS_STRUCTURE; int componentCount = typeSpec->typeSpec.structure.elementCount; self->value.structure.size = componentCount; - self->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); + self->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; for (i = 0; i < componentCount; i++) { @@ -1234,24 +1265,24 @@ MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec) value = MmsValue_newUnsigned(typeSpec->typeSpec.unsignedInteger); break; case MMS_FLOAT: - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_FLOAT; value->value.floatingPoint.exponentWidth = typeSpec->typeSpec.floatingpoint.exponentWidth; value->value.floatingPoint.formatWidth = typeSpec->typeSpec.floatingpoint.formatWidth; - value->value.floatingPoint.buf = (uint8_t*) calloc(1, typeSpec->typeSpec.floatingpoint.formatWidth / 8); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_CALLOC(1, typeSpec->typeSpec.floatingpoint.formatWidth / 8); break; case MMS_BIT_STRING: - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BIT_STRING; { int bitSize = abs(typeSpec->typeSpec.bitString); value->value.bitString.size = bitSize; int size = (bitSize / 8) + ((bitSize % 8) > 0); - value->value.bitString.buf = (uint8_t*) calloc(1, size); + value->value.bitString.buf = (uint8_t*) GLOBAL_CALLOC(1, size); } break; case MMS_OCTET_STRING: - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; if (typeSpec->typeSpec.octetString < 0) @@ -1260,7 +1291,7 @@ MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec) value->value.octetString.size = typeSpec->typeSpec.octetString; value->value.octetString.maxSize = abs(typeSpec->typeSpec.octetString); - value->value.octetString.buf = (uint8_t*) calloc(1, abs(typeSpec->typeSpec.octetString)); + value->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, abs(typeSpec->typeSpec.octetString)); break; case MMS_VISIBLE_STRING: value = MmsValue_newVisibleStringWithSize(abs(typeSpec->typeSpec.visibleString)); @@ -1269,7 +1300,7 @@ MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec) value = MmsValue_newBoolean(false); break; case MMS_UTC_TIME: - value = (MmsValue*) calloc(1, sizeof(MmsValue)); + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; break; case MMS_ARRAY: @@ -1307,8 +1338,8 @@ setVisibleStringValue(MmsValue* value, char* string) int newStringSize = strlen(string); if (newStringSize > value->value.visibleString.size) { - free(value->value.visibleString.buf); - value->value.visibleString.buf = (char*) malloc(newStringSize + 1); + GLOBAL_FREEMEM(value->value.visibleString.buf); + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(newStringSize + 1); value->value.visibleString.size = newStringSize; } @@ -1323,7 +1354,7 @@ setVisibleStringValue(MmsValue* value, char* string) static MmsValue* MmsValue_newString(char* string, MmsType type) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = type; if (string == NULL) { @@ -1334,7 +1365,7 @@ MmsValue_newString(char* string, MmsType type) int stringSize = strlen(string); value->value.visibleString.size = stringSize; - value->value.visibleString.buf = (char*) malloc(stringSize + 1); + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(stringSize + 1); setVisibleStringValue(value, string); } @@ -1352,11 +1383,11 @@ MmsValue_newVisibleString(char* string) static MmsValue* MmsValue_newStringWithSize(int size, MmsType type) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = type; value->value.visibleString.size = size; - value->value.visibleString.buf = (char*) malloc(size + 1); + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(size + 1); value->value.visibleString.buf[0] = 0; return value; @@ -1384,7 +1415,7 @@ MmsValue_newMmsStringWithSize(int size) MmsValue* MmsValue_newBinaryTime(bool timeOfDay) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; if (timeOfDay == true) @@ -1485,7 +1516,7 @@ MmsValue_setMmsString(MmsValue* value, char* string) static MmsValue* MmsValue_newStringFromByteArray(uint8_t* byteArray, int size, MmsType type) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = type; value->value.visibleString.buf = createStringFromBuffer(byteArray, size); @@ -1528,7 +1559,7 @@ MmsValue_toString(MmsValue* value) MmsValue* MmsValue_newUtcTime(uint32_t timeval) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; uint8_t* timeArray = (uint8_t*) &timeval; @@ -1553,7 +1584,7 @@ MmsValue_newUtcTime(uint32_t timeval) MmsValue* MmsValue_newUtcTimeByMsTime(uint64_t timeval) { - MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; MmsValue_setUtcTimeMs(value, timeval); @@ -1564,11 +1595,11 @@ MmsValue_newUtcTimeByMsTime(uint64_t timeval) MmsValue* MmsValue_createArray(MmsVariableSpecification* elementType, int size) { - MmsValue* array = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* array = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); array->type = MMS_ARRAY; array->value.structure.size = size; - array->value.structure.components = (MmsValue**) calloc(size, sizeof(MmsValue*)); + array->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*)); int i; for (i = 0; i < size; i++) { @@ -1581,11 +1612,11 @@ MmsValue_createArray(MmsVariableSpecification* elementType, int size) MmsValue* MmsValue_createEmtpyArray(int size) { - MmsValue* array = (MmsValue*) calloc(1, sizeof(MmsValue)); + MmsValue* array = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); array->type = MMS_ARRAY; array->value.structure.size = size; - array->value.structure.components = (MmsValue**) calloc(size, sizeof(MmsValue*)); + array->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*)); int i; for (i = 0; i < size; i++) { diff --git a/src/mms/iso_mms/server/mms_device.c b/src/mms/iso_mms/server/mms_device.c index 53d15732..f071a63f 100644 --- a/src/mms/iso_mms/server/mms_device.c +++ b/src/mms/iso_mms/server/mms_device.c @@ -21,13 +21,14 @@ * See COPYING file for the complete license text. */ +#include "mms_server_internal.h" #include "mms_device_model.h" #include "stack_config.h" MmsDevice* MmsDevice_create(char* deviceName) { - MmsDevice* self = (MmsDevice*) calloc(1, sizeof(MmsDevice)); + MmsDevice* self = (MmsDevice*) GLOBAL_CALLOC(1, sizeof(MmsDevice)); self->deviceName = deviceName; self->namedVariableLists = LinkedList_create(); @@ -56,8 +57,8 @@ MmsDevice_destroy(MmsDevice* self) LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy); - free(self->domains); - free(self); + GLOBAL_FREEMEM(self->domains); + GLOBAL_FREEMEM(self); } MmsDomain* diff --git a/src/mms/iso_mms/server/mms_domain.c b/src/mms/iso_mms/server/mms_domain.c index 3ec82e2c..7d07dc39 100644 --- a/src/mms/iso_mms/server/mms_domain.c +++ b/src/mms/iso_mms/server/mms_domain.c @@ -3,22 +3,22 @@ * * Copyright 2013, 2014 Michael Zillgith * - * This file is part of libIEC61850. + * This file is part of libIEC61850. * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . * - * See COPYING file for the complete license text. + * See COPYING file for the complete license text. */ #include "mms_device_model.h" @@ -36,7 +36,7 @@ freeNamedVariables(MmsVariableSpecification** variables, int variablesCount) MmsDomain* MmsDomain_create(char* domainName) { - MmsDomain* self = (MmsDomain*) calloc(1, sizeof(MmsDomain)); + MmsDomain* self = (MmsDomain*) GLOBAL_CALLOC(1, sizeof(MmsDomain)); self->domainName = copyString(domainName); self->namedVariableLists = LinkedList_create(); @@ -47,18 +47,18 @@ MmsDomain_create(char* domainName) void MmsDomain_destroy(MmsDomain* self) { - free(self->domainName); + GLOBAL_FREEMEM(self->domainName); if (self->namedVariables != NULL) { freeNamedVariables(self->namedVariables, self->namedVariablesCount); - free(self->namedVariables); + GLOBAL_FREEMEM(self->namedVariables); } LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy); - free(self); + GLOBAL_FREEMEM(self); } char* @@ -70,8 +70,6 @@ MmsDomain_getName(MmsDomain* self) bool MmsDomain_addNamedVariableList(MmsDomain* self, MmsNamedVariableList variableList) { - //TODO check if operation is allowed! - LinkedList_add(self->namedVariableLists, variableList); return true; diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c index a2af0378..ce1833df 100644 --- a/src/mms/iso_mms/server/mms_file_service.c +++ b/src/mms/iso_mms/server/mms_file_service.c @@ -25,7 +25,7 @@ #if (MMS_FILE_SERVICE == 1) -#include "filesystem.h" +#include "hal_filesystem.h" #include "conversions.h" #define CONFIG_MMS_FILE_SERVICE_MAX_FILENAME_LENGTH 256 diff --git a/src/mms/iso_mms/server/mms_get_namelist_service.c b/src/mms/iso_mms/server/mms_get_namelist_service.c index 31d6600e..a6c5b37a 100644 --- a/src/mms/iso_mms/server/mms_get_namelist_service.c +++ b/src/mms/iso_mms/server/mms_get_namelist_service.c @@ -84,7 +84,7 @@ appendMmsSubVariable(char* name, char* child) int newSize = nameLen + childLen + 2; - char* newName = (char*) malloc(newSize); + char* newName = (char*) GLOBAL_MALLOC(newSize); int bufPos = 0; int i; diff --git a/src/mms/iso_mms/server/mms_get_var_access_service.c b/src/mms/iso_mms/server/mms_get_var_access_service.c index 97d3d81e..92201944 100644 --- a/src/mms/iso_mms/server/mms_get_var_access_service.c +++ b/src/mms/iso_mms/server/mms_get_var_access_service.c @@ -42,7 +42,7 @@ createTypeSpecification ( (long) namedVariable->typeSpec.array.elementCount); typeSpec->choice.array.packed = NULL; - typeSpec->choice.array.elementType = (TypeSpecification_t*) calloc(1, sizeof(TypeSpecification_t)); + typeSpec->choice.array.elementType = (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); createTypeSpecification(namedVariable->typeSpec.array.elementTypeSpec, typeSpec->choice.array.elementType); @@ -57,17 +57,17 @@ createTypeSpecification ( typeSpec->choice.structure.components.list.size = componentCount; typeSpec->choice.structure.components.list.array - = (StructComponent_t**) calloc(componentCount, sizeof(StructComponent_t*)); + = (StructComponent_t**) GLOBAL_CALLOC(componentCount, sizeof(StructComponent_t*)); int i; for (i = 0; i < componentCount; i++) { typeSpec->choice.structure.components.list.array[i] = - (StructComponent_t*) calloc(1, sizeof(StructComponent_t)); + (StructComponent_t*) GLOBAL_CALLOC(1, sizeof(StructComponent_t)); typeSpec->choice.structure.components.list.array[i]->componentName = - (Identifier_t*) calloc(1, sizeof(Identifier_t)); + (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t)); typeSpec->choice.structure.components.list.array[i]->componentName->buf = (uint8_t*) copyString(namedVariable->typeSpec.structure.elements[i]->name); @@ -76,7 +76,7 @@ createTypeSpecification ( strlen(namedVariable->typeSpec.structure.elements[i]->name); typeSpec->choice.structure.components.list.array[i]->componentType = - (TypeSpecification_t*) calloc(1, sizeof(TypeSpecification_t)); + (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t)); createTypeSpecification(namedVariable->typeSpec.structure.elements[i], typeSpec->choice.structure.components.list.array[i]->componentType); @@ -151,19 +151,19 @@ freeTypeSpecRecursive(TypeSpecification_t* typeSpec) { int i; for (i = 0; i < elementCount; i++) { - free(typeSpec->choice.structure.components.list.array[i]->componentName->buf); - free(typeSpec->choice.structure.components.list.array[i]->componentName); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName->buf); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName); freeTypeSpecRecursive(typeSpec->choice.structure.components.list.array[i]->componentType); - free(typeSpec->choice.structure.components.list.array[i]->componentType); - free(typeSpec->choice.structure.components.list.array[i]); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentType); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]); } - free(typeSpec->choice.structure.components.list.array); + GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array); } else if (typeSpec->present == TypeSpecification_PR_array) { - free(typeSpec->choice.array.numberOfElements.buf); + GLOBAL_FREEMEM(typeSpec->choice.array.numberOfElements.buf); freeTypeSpecRecursive(typeSpec->choice.array.elementType); - free(typeSpec->choice.array.elementType); + GLOBAL_FREEMEM(typeSpec->choice.array.elementType); } } @@ -176,27 +176,27 @@ deleteVariableAccessAttributesResponse( int i; for (i = 0; i < count; i++) { - free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf); - free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName); TypeSpecification_t* typeSpec = getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentType; freeTypeSpecRecursive(typeSpec); - free(typeSpec); - free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]); + GLOBAL_FREEMEM(typeSpec); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]); } - free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array); getVarAccessAttr->typeSpecification.choice.structure.components.list.array = NULL; getVarAccessAttr->typeSpecification.choice.structure.components.list.count = 0; getVarAccessAttr->typeSpecification.choice.structure.components.list.size = 0; } else if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_array) { - free(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf); getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf = NULL; getVarAccessAttr->typeSpecification.choice.array.numberOfElements.size = 0; freeTypeSpecRecursive(getVarAccessAttr->typeSpecification.choice.array.elementType); - free(getVarAccessAttr->typeSpecification.choice.array.elementType); + GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.elementType); getVarAccessAttr->typeSpecification.choice.array.elementType = NULL; } @@ -301,8 +301,8 @@ mmsServer_handleGetVariableAccessAttributesRequest( createVariableAccessAttributesResponse(connection, domainIdStr, nameIdStr, invokeId, response); - free(domainIdStr); - free(nameIdStr); + GLOBAL_FREEMEM(domainIdStr); + GLOBAL_FREEMEM(nameIdStr); } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) else if (request->choice.name.present == ObjectName_PR_vmdspecific) { @@ -314,7 +314,7 @@ mmsServer_handleGetVariableAccessAttributesRequest( createVariableAccessAttributesResponse(connection, NULL, nameIdStr, invokeId, response); - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); } #endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */ else { diff --git a/src/mms/iso_mms/server/mms_information_report.c b/src/mms/iso_mms/server/mms_information_report.c index 2349df73..4380d727 100644 --- a/src/mms/iso_mms/server/mms_information_report.c +++ b/src/mms/iso_mms/server/mms_information_report.c @@ -97,19 +97,18 @@ MmsServerConnection_sendInformationReportListOfVariables( uint32_t varSpecSize = BerEncoder_determineEncodedStringSize(spec->itemId); - if (spec->domainId != NULL) { + if (spec->domainId != NULL) varSpecSize += BerEncoder_determineEncodedStringSize(spec->domainId); - varSpecSize += BerEncoder_determineLengthSize(varSpecSize) + 1; - } - listOfVarSpecSize += varSpecSize; + uint32_t sequenceSize = (varSpecSize + 1 + BerEncoder_determineLengthSize(varSpecSize)); + + listOfVarSpecSize += (1 + BerEncoder_determineLengthSize(sequenceSize) + sequenceSize); i++; specElement = LinkedList_getNext(specElement); } - uint32_t sequenceSize = 1 + BerEncoder_determineLengthSize(listOfVarSpecSize) + listOfVarSpecSize; - uint32_t listOfVariableSize = 1 + BerEncoder_determineLengthSize(sequenceSize) + sequenceSize; + uint32_t listOfVariableSize = 1 + BerEncoder_determineLengthSize(listOfVarSpecSize) + listOfVarSpecSize; uint32_t accessResultSize = 0; @@ -146,7 +145,7 @@ MmsServerConnection_sendInformationReportListOfVariables( /* encode list of variable access specifications */ bufPos = BerEncoder_encodeTL(0xa0, listOfVariableSize, buffer, bufPos); - bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos); + specElement = LinkedList_getNext(variableAccessDeclarations); i = 0; @@ -160,13 +159,17 @@ MmsServerConnection_sendInformationReportListOfVariables( varSpecSize += BerEncoder_determineEncodedStringSize(spec->domainId); uint32_t varSpecSizeComplete = varSpecSize + BerEncoder_determineLengthSize(varSpecSize) + 1; + uint32_t sequenceSize = varSpecSizeComplete + BerEncoder_determineLengthSize(varSpecSizeComplete) + 1; + bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos); bufPos = BerEncoder_encodeTL(0xa0, varSpecSizeComplete, buffer, bufPos); /* domain-specific */ bufPos = BerEncoder_encodeTL(0xa1, varSpecSize, buffer, bufPos); bufPos = BerEncoder_encodeStringWithTag(0x1a, spec->domainId, buffer, bufPos); bufPos = BerEncoder_encodeStringWithTag(0x1a, spec->itemId, buffer, bufPos); } else { + uint32_t sequenceSize = varSpecSize + BerEncoder_determineLengthSize(varSpecSize) + 1; + bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos); bufPos = BerEncoder_encodeTL(0xa0, varSpecSize, buffer, bufPos); /* vmd-specific */ bufPos = BerEncoder_encodeStringWithTag(0x80, spec->itemId, buffer, bufPos); } diff --git a/src/mms/iso_mms/server/mms_named_variable_list.c b/src/mms/iso_mms/server/mms_named_variable_list.c index bd318301..9fe16a9c 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list.c +++ b/src/mms/iso_mms/server/mms_named_variable_list.c @@ -28,7 +28,7 @@ MmsNamedVariableListEntry MmsNamedVariableListEntry_create(MmsAccessSpecifier accessSpecifier) { - MmsNamedVariableListEntry listEntry = (MmsNamedVariableListEntry) malloc(sizeof(MmsAccessSpecifier)); + MmsNamedVariableListEntry listEntry = (MmsNamedVariableListEntry) GLOBAL_MALLOC(sizeof(MmsAccessSpecifier)); listEntry->domain = accessSpecifier.domain; listEntry->variableName = copyString(accessSpecifier.variableName); @@ -45,8 +45,8 @@ MmsNamedVariableListEntry_create(MmsAccessSpecifier accessSpecifier) void MmsNamedVariableListEntry_destroy(MmsNamedVariableListEntry self) { - free(self->variableName); - free(self); + GLOBAL_FREEMEM(self->variableName); + GLOBAL_FREEMEM(self); } @@ -64,7 +64,7 @@ MmsNamedVariableListEntry_getVariableName(MmsNamedVariableListEntry self) { MmsNamedVariableList MmsNamedVariableList_create(char* name, bool deletable) { - MmsNamedVariableList self = (MmsNamedVariableList) malloc(sizeof(struct sMmsNamedVariableList)); + MmsNamedVariableList self = (MmsNamedVariableList) GLOBAL_MALLOC(sizeof(struct sMmsNamedVariableList)); self->deletable = deletable; self->name = copyString(name); @@ -108,8 +108,8 @@ void MmsNamedVariableList_destroy(MmsNamedVariableList self) { LinkedList_destroyDeep(self->listOfVariables, deleteVariableListEntry); - free(self->name); - free(self); + GLOBAL_FREEMEM(self->name); + GLOBAL_FREEMEM(self); } diff --git a/src/mms/iso_mms/server/mms_named_variable_list_service.c b/src/mms/iso_mms/server/mms_named_variable_list_service.c index 61d7ebd1..e12a3c07 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list_service.c +++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c @@ -1,7 +1,7 @@ /* * mms_named_variable_list_service.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2014 Michael Zillgith * * This file is part of libIEC61850. * @@ -29,8 +29,20 @@ #if (MMS_DATA_SET_SERVICE == 1) - #if (MMS_DYNAMIC_DATA_SETS == 1) + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS +#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10 +#endif + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS +#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10 +#endif + +#ifndef CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS +#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10 +#endif + static void createDeleteNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response, uint32_t numberMatched, uint32_t numberDeleted) @@ -134,9 +146,8 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection* connection, MmsServerConnection_deleteNamedVariableList(connection, itemId); } - free(itemId); + GLOBAL_FREEMEM(itemId); } - //TODO else send error??? } createDeleteNamedVariableListResponse(invokeId, response, numberMatched, numberDeleted); @@ -168,10 +179,39 @@ createDefineNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response) response->size = bufPos; } +static bool +checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier) +{ + if (accessSpecifier->domain == NULL) + return false; + + MmsVariableSpecification* variableSpec = + MmsDomain_getNamedVariable(accessSpecifier->domain, accessSpecifier->variableName); + + if (variableSpec == NULL) + return false; + + if (accessSpecifier->arrayIndex != -1) { + if (variableSpec->type != MMS_ARRAY) + return false; + + if (accessSpecifier->arrayIndex >= variableSpec->typeSpec.array.elementCount) + return false; + + if (accessSpecifier->componentName != NULL) { + if (MmsVariableSpecification_getNamedVariableRecursive(variableSpec, accessSpecifier->componentName) == NULL) + return false; + } + } + + return true; +} + + static MmsNamedVariableList createNamedVariableList(MmsDevice* device, DefineNamedVariableListRequest_t* request, - char* variableListName) + char* variableListName, MmsError* mmsError) { MmsNamedVariableList namedVariableList = MmsNamedVariableList_create(variableListName, true); @@ -199,10 +239,11 @@ createNamedVariableList(MmsDevice* device, struct AlternateAccess__Member* alternateAccess = request->listOfVariable.list.array[i]->alternateAccess->list.array[0]; - if (alternateAccess->present == AlternateAccess__Member_PR_unnamed) + if ((alternateAccess->present == AlternateAccess__Member_PR_unnamed) + &&(alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) + && (alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.present == + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index)) { - //TODO add checks! - asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.index), &arrayIndex); @@ -215,6 +256,7 @@ createNamedVariableList(MmsDevice* device, else { MmsNamedVariableList_destroy(namedVariableList); namedVariableList = NULL; + *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS; break; } @@ -240,17 +282,28 @@ createNamedVariableList(MmsDevice* device, accessSpecifier.arrayIndex = arrayIndex; accessSpecifier.componentName = componentName; - MmsNamedVariableListEntry variable = - MmsNamedVariableListEntry_create(accessSpecifier); + // check if element exists + if (checkIfVariableExists(device, &accessSpecifier) == true) { - MmsNamedVariableList_addVariable(namedVariableList, variable); + MmsNamedVariableListEntry variable = + MmsNamedVariableListEntry_create(accessSpecifier); - free(domainId); - free(variableName); + MmsNamedVariableList_addVariable(namedVariableList, variable); + } + else { + MmsNamedVariableList_destroy(namedVariableList); + namedVariableList = NULL; + i = variableCount; // exit loop after freeing loop variables + *mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED; + } + + GLOBAL_FREEMEM(domainId); + GLOBAL_FREEMEM(variableName); } else { MmsNamedVariableList_destroy(namedVariableList); namedVariableList = NULL; + *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS; break; } } @@ -286,60 +339,75 @@ mmsServer_handleDefineNamedVariableListRequest( MmsDomain* domain = MmsDevice_getDomain(device, domainName); - free(domainName); + GLOBAL_FREEMEM(domainName); if (domain == NULL) { mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); return; } - char* variableListName = createStringFromBuffer( - request->variableListName.choice.domainspecific.itemId.buf, - request->variableListName.choice.domainspecific.itemId.size); + if (LinkedList_size(domain->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS) { + char* variableListName = createStringFromBuffer( + request->variableListName.choice.domainspecific.itemId.buf, + request->variableListName.choice.domainspecific.itemId.size); - if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) { - mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); - } - else { - MmsNamedVariableList namedVariableList = createNamedVariableList(device, - request, variableListName); - - if (namedVariableList != NULL) { - MmsDomain_addNamedVariableList(domain, namedVariableList); - createDefineNamedVariableListResponse(invokeId, response); - } - else - mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; + + MmsNamedVariableList namedVariableList = createNamedVariableList(device, + request, variableListName, &mmsError); + + if (namedVariableList != NULL) { + MmsDomain_addNamedVariableList(domain, namedVariableList); + createDefineNamedVariableListResponse(invokeId, response); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError); + } + + GLOBAL_FREEMEM(variableListName); } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); + - free(variableListName); } else if (request->variableListName.present == ObjectName_PR_aaspecific) { - char* variableListName = createStringFromBuffer( - request->variableListName.choice.aaspecific.buf, - request->variableListName.choice.aaspecific.size); + if (LinkedList_size(connection->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS) { + char* variableListName = createStringFromBuffer( + request->variableListName.choice.aaspecific.buf, + request->variableListName.choice.aaspecific.size); - if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) { - mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); - } - else { - MmsNamedVariableList namedVariableList = createNamedVariableList(device, - request, variableListName); - if (namedVariableList != NULL) { - MmsServerConnection_addNamedVariableList(connection, namedVariableList); - createDefineNamedVariableListResponse(invokeId, response); + if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) { + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS); + } + else { + MmsError mmsError; + + MmsNamedVariableList namedVariableList = createNamedVariableList(device, + request, variableListName, &mmsError); + + if (namedVariableList != NULL) { + MmsServerConnection_addNamedVariableList(connection, namedVariableList); + createDefineNamedVariableListResponse(invokeId, response); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError); } - else - mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); - } - free(variableListName); + GLOBAL_FREEMEM(variableListName); + } + else + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE); } else - mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); + mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED); asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); } @@ -371,7 +439,7 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, varListResponse->listOfVariable.list.size = variableCount; varListResponse->listOfVariable.list.array = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member**) - calloc(variableCount, sizeof(void*)); + GLOBAL_CALLOC(variableCount, sizeof(void*)); LinkedList variable = LinkedList_getNext(variables); @@ -380,7 +448,7 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data; varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*) - calloc(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member)); + GLOBAL_CALLOC(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member)); varListResponse->listOfVariable.list.array[i]->variableSpecification.present = VariableSpecification_PR_name; @@ -454,8 +522,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest( mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - free(domainName); - free(itemName); + GLOBAL_FREEMEM(domainName); + GLOBAL_FREEMEM(itemName); } else { mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 4a9fea2c..80399ec7 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -78,7 +78,7 @@ addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnecti MmsValue_setElement(value, i, element); - free(newNameIdStr); + GLOBAL_FREEMEM(newNameIdStr); } } } diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 3e9fa375..42550b3d 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -49,7 +49,7 @@ createValueCaches(MmsDevice* device) MmsServer MmsServer_create(IsoServer isoServer, MmsDevice* device) { - MmsServer self = (MmsServer) malloc(sizeof(struct sMmsServer)); + MmsServer self = (MmsServer) GLOBAL_MALLOC(sizeof(struct sMmsServer)); memset(self, 0, sizeof(struct sMmsServer)); @@ -58,9 +58,12 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device) self->openConnections = Map_create(); self->valueCaches = createValueCaches(device); self->isLocked = false; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) self->modelMutex = Semaphore_create(1); IsoServer_setUserLock(isoServer, self->modelMutex); +#endif return self; } @@ -68,24 +71,35 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device) void MmsServer_lockModel(MmsServer self) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->modelMutex); +#endif } void MmsServer_unlockModel(MmsServer self) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->modelMutex); +#endif } void -MmsServer_installReadHandler(MmsServer self, ReadVariableHandler readHandler, void* parameter) +MmsServer_installReadHandler(MmsServer self, MmsReadVariableHandler readHandler, void* parameter) { self->readHandler = readHandler; self->readHandlerParameter = parameter; } void -MmsServer_installWriteHandler(MmsServer self, WriteVariableHandler writeHandler, void* parameter) +MmsServer_installReadAccessHandler(MmsServer self, MmsReadAccessHandler readAccessHandler, void* parameter) +{ + self->readAccessHandler = readAccessHandler; + self->readAccessHandlerParameter = parameter; +} + +void +MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler writeHandler, void* parameter) { self->writeHandler = writeHandler; self->writeHandlerParameter = parameter; @@ -124,8 +138,12 @@ MmsServer_destroy(MmsServer self) { Map_deleteDeep(self->openConnections, false, closeConnection); Map_deleteDeep(self->valueCaches, false, (void (*) (void*)) deleteSingleCache); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_destroy(self->modelMutex); - free(self); +#endif + + GLOBAL_FREEMEM(self); } MmsValue* @@ -177,11 +195,20 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va return indication; } + MmsValue* mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection* connection) { MmsValue* value = NULL; + if (self->readAccessHandler != NULL) { + MmsDataAccessError accessError = + self->readAccessHandler(self->readAccessHandlerParameter, domain, itemId, connection); + + if (accessError != DATA_ACCESS_ERROR_SUCCESS) + return NULL; + } + value = MmsServer_getValueFromCache(self, domain, itemId); if (value == NULL) @@ -233,6 +260,7 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication, } } +#if (CONFIG_MMS_THREADLESS_STACK != 1) void MmsServer_startListening(MmsServer server, int tcpPort) { @@ -246,3 +274,31 @@ MmsServer_stopListening(MmsServer server) { IsoServer_stopListening(server->isoServer); } +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1)*/ + +void +MmsServer_startListeningThreadless(MmsServer self, int tcpPort) +{ + IsoServer_setConnectionHandler(self->isoServer, isoConnectionIndicationHandler, (void*) self); + IsoServer_setTcpPort(self->isoServer, tcpPort); + IsoServer_startListeningThreadless(self->isoServer); +} + +int +MmsServer_waitReady(MmsServer self, unsigned int timeoutMs) +{ + return IsoServer_waitReady(self->isoServer, timeoutMs); +} + +void +MmsServer_handleIncomingMessages(MmsServer self) +{ + IsoServer_processIncomingMessages(self->isoServer); +} + +void +MmsServer_stopListeningThreadless(MmsServer self) +{ + IsoServer_stopListeningThreadless(self->isoServer); +} + diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c index c34220aa..31348c57 100644 --- a/src/mms/iso_mms/server/mms_server_common.c +++ b/src/mms/iso_mms/server/mms_server_common.c @@ -34,7 +34,7 @@ mmsServer_write_out(const void *buffer, size_t size, void *app_key) MmsPdu_t* mmsServer_createConfirmedResponse(uint32_t invokeId) { - MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t)); + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); mmsPdu->present = MmsPdu_PR_confirmedResponsePdu; @@ -48,7 +48,7 @@ mmsServer_createConfirmedResponse(uint32_t invokeId) void mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsError errorType) { - MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t)); + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); mmsPdu->present = MmsPdu_PR_confirmedErrorPDU; asn_long2INTEGER(&(mmsPdu->choice.confirmedErrorPDU.invokeID), @@ -87,6 +87,18 @@ mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsEr asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, ServiceError__errorClass__definition_objectexists); } + else if (errorType == MMS_ERROR_DEFINITION_OBJECT_UNDEFINED) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_definition; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__definition_objectundefined); + } + else if (errorType == MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_definition; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__definition_typeunsupported); + } else if (errorType == MMS_ERROR_FILE_FILE_NON_EXISTENT) { mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = ServiceError__errorClass_PR_file; @@ -105,6 +117,12 @@ mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsEr asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, ServiceError__errorClass__resource_other); } + else if (errorType == MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE) { + mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present = + ServiceError__errorClass_PR_resource; + asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access, + ServiceError__errorClass__resource_capabilityunavailable); + } der_encode(&asn_DEF_MmsPdu, mmsPdu, mmsServer_write_out, (void*) response); @@ -188,7 +206,7 @@ mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListNa if (strcmp(MmsNamedVariableList_getName(varList), variableListName) == 0) { previousElement->next = element->next; - free(element); + GLOBAL_FREEMEM(element); MmsNamedVariableList_destroy(varList); break; diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c index 66cbff4f..3292d6c3 100644 --- a/src/mms/iso_mms/server/mms_server_connection.c +++ b/src/mms/iso_mms/server/mms_server_connection.c @@ -38,12 +38,12 @@ void mmsServer_writeMmsRejectPdu(uint32_t* invokeId, int reason, ByteBuffer* response) { - MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t)); + MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t)); mmsPdu->present = MmsPdu_PR_rejectPDU; if (invokeId != NULL) { - mmsPdu->choice.rejectPDU.originalInvokeID = (Unsigned32_t*) calloc(1, sizeof(Unsigned32_t)); + mmsPdu->choice.rejectPDU.originalInvokeID = (Unsigned32_t*) GLOBAL_CALLOC(1, sizeof(Unsigned32_t)); asn_long2INTEGER(mmsPdu->choice.rejectPDU.originalInvokeID, *invokeId); } @@ -291,7 +291,7 @@ MmsServerConnection_init(MmsServerConnection* connection, MmsServer server, IsoC MmsServerConnection* self; if (connection == NULL) - self = (MmsServerConnection*) calloc(1, sizeof(MmsServerConnection)); + self = (MmsServerConnection*) GLOBAL_CALLOC(1, sizeof(MmsServerConnection)); else self = connection; @@ -321,7 +321,7 @@ MmsServerConnection_destroy(MmsServerConnection* self) #endif LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy); - free(self); + GLOBAL_FREEMEM(self); } bool diff --git a/src/mms/iso_mms/server/mms_value_cache.c b/src/mms/iso_mms/server/mms_value_cache.c index ae584eeb..161ae9b9 100644 --- a/src/mms/iso_mms/server/mms_value_cache.c +++ b/src/mms/iso_mms/server/mms_value_cache.c @@ -40,7 +40,7 @@ typedef struct sMmsValueCacheEntry { MmsValueCache MmsValueCache_create(MmsDomain* domain) { - MmsValueCache self = (MmsValueCache) calloc(1, sizeof(struct sMmsValueCache)); + MmsValueCache self = (MmsValueCache) GLOBAL_CALLOC(1, sizeof(struct sMmsValueCache)); self->domain = domain; @@ -55,7 +55,7 @@ MmsValueCache_insertValue(MmsValueCache self, char* itemId, MmsValue* value) MmsVariableSpecification* typeSpec = MmsDomain_getNamedVariable(self->domain, itemId); if (typeSpec != NULL) { - MmsValueCacheEntry* cacheEntry = (MmsValueCacheEntry*) malloc(sizeof(MmsValueCacheEntry)); + MmsValueCacheEntry* cacheEntry = (MmsValueCacheEntry*) GLOBAL_MALLOC(sizeof(MmsValueCacheEntry)); cacheEntry->value = value; cacheEntry->typeSpec = typeSpec; @@ -135,7 +135,7 @@ MmsValueCache_lookupValue(MmsValueCache self, char* itemId) value = searchCacheForValue(self, itemId, parentItemId); } - free(itemIdCopy); + GLOBAL_FREEMEM(itemIdCopy); } if (cacheEntry != NULL) @@ -149,7 +149,7 @@ cacheEntryDelete(MmsValueCacheEntry* entry) { if (entry != NULL) { MmsValue_delete(entry->value); - free(entry); + GLOBAL_FREEMEM(entry); } } @@ -157,5 +157,5 @@ void MmsValueCache_destroy(MmsValueCache self) { Map_deleteDeep(self->map, true, (void (*) (void*)) cacheEntryDelete); - free(self); + GLOBAL_FREEMEM(self); } diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c index 26deacdb..afd531a7 100644 --- a/src/mms/iso_mms/server/mms_write_service.c +++ b/src/mms/iso_mms/server/mms_write_service.c @@ -47,13 +47,13 @@ mmsServer_createMmsWriteResponse(MmsServerConnection* connection, writeResponse->list.count = numberOfItems; writeResponse->list.size = numberOfItems; - writeResponse->list.array = (struct WriteResponse__Member**) calloc(numberOfItems, + writeResponse->list.array = (struct WriteResponse__Member**) GLOBAL_CALLOC(numberOfItems, sizeof(struct WriteResponse__Member*)); int i; for (i = 0; i < numberOfItems; i++) { - writeResponse->list.array[i] = (struct WriteResponse__Member*) calloc(1, sizeof(struct WriteResponse__Member)); + writeResponse->list.array[i] = (struct WriteResponse__Member*) GLOBAL_CALLOC(1, sizeof(struct WriteResponse__Member)); if (accessResults[i] == DATA_ACCESS_ERROR_SUCCESS) writeResponse->list.array[i]->present = WriteResponse__Member_PR_success; @@ -72,13 +72,13 @@ mmsServer_createMmsWriteResponse(MmsServerConnection* connection, void -MmsServerConnection_sendWriteResponse(MmsServerConnection* self, uint32_t invokeId, MmsDataAccessError indication) +MmsServerConnection_sendWriteResponse(MmsServerConnection* self, uint32_t invokeId, MmsDataAccessError indication, bool handlerMode) { ByteBuffer* response = ByteBuffer_create(NULL, self->maxPduSize); mmsServer_createMmsWriteResponse(self, invokeId, response, 1, &indication); - IsoConnection_sendMessage(self->isoConnection, response, false); + IsoConnection_sendMessage(self->isoConnection, response, handlerMode); ByteBuffer_destroy(response); } @@ -151,7 +151,7 @@ mmsServer_handleWriteRequest( domain = MmsDevice_getDomain(device, domainIdStr); - free(domainIdStr); + GLOBAL_FREEMEM(domainIdStr); if (domain == NULL) { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; @@ -180,7 +180,7 @@ mmsServer_handleWriteRequest( } if (variable == NULL) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; continue; } @@ -189,13 +189,13 @@ mmsServer_handleWriteRequest( if (alternateAccess != NULL) { if (variable->type != MMS_ARRAY) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } if (!mmsServer_isIndexAccess(alternateAccess)) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; continue; } @@ -206,7 +206,7 @@ mmsServer_handleWriteRequest( MmsValue* value = mmsMsg_parseDataElement(dataElement); if (value == NULL) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } @@ -219,7 +219,7 @@ mmsServer_handleWriteRequest( MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); if (cachedArray == NULL) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; @@ -230,20 +230,20 @@ mmsServer_handleWriteRequest( MmsValue* elementValue = MmsValue_getElement(cachedArray, index); if (elementValue == NULL) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; } if (MmsValue_update(elementValue, value) == false) { - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; continue; } - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); MmsValue_delete(value); accessResults[i] = DATA_ACCESS_ERROR_SUCCESS; continue; @@ -260,7 +260,7 @@ mmsServer_handleWriteRequest( MmsValue_delete(value); - free(nameIdStr); + GLOBAL_FREEMEM(nameIdStr); } if (sendResponse) { diff --git a/src/mms/iso_server/iso_connection.c b/src/mms/iso_server/iso_connection.c index f3539b71..19201cd5 100644 --- a/src/mms/iso_server/iso_connection.c +++ b/src/mms/iso_server/iso_connection.c @@ -24,15 +24,14 @@ #include "libiec61850_platform_includes.h" #include "stack_config.h" -#include "byte_stream.h" #include "buffer_chain.h" #include "cotp.h" #include "iso_session.h" #include "iso_presentation.h" #include "acse.h" #include "iso_server.h" -#include "socket.h" -#include "thread.h" +#include "hal_socket.h" +#include "hal_thread.h" #include "iso_server_private.h" @@ -47,6 +46,8 @@ #define RECEIVE_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100 #define SEND_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100 +#define TPKT_RFC1006_HEADER_SIZE 4 + #define ISO_CON_STATE_RUNNING 1 #define ISO_CON_STATE_STOPPED 0 @@ -54,353 +55,448 @@ struct sIsoConnection { uint8_t* receiveBuffer; uint8_t* sendBuffer; + + ByteBuffer rcvBuffer; + + uint8_t* cotpReadBuf; + uint8_t* cotpWriteBuf; + ByteBuffer cotpReadBuffer; + ByteBuffer cotpWriteBuffer; + MessageReceivedHandler msgRcvdHandler; - IsoServer isoServer; void* msgRcvdHandlerParameter; + + IsoServer isoServer; + Socket socket; int state; IsoSession* session; IsoPresentation* presentation; CotpConnection* cotpConnection; + + AcseConnection* acseConnection; + char* clientAddress; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) Thread thread; Semaphore conMutex; - - void* securityToken; + bool isInsideCallback; +#endif }; static void -handleTcpConnection(IsoConnection self) +finalizeIsoConnection(IsoConnection self) { if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: connection %p started\n", self); + printf("ISO_SERVER: finalizeIsoConnection --> close transport connection\n"); - CotpIndication cotpIndication; + IsoServer_closeConnection(self->isoServer, self); + if (self->socket != NULL) + Socket_destroy(self->socket); - IsoSessionIndication sIndication; + GLOBAL_FREEMEM(self->session); + GLOBAL_FREEMEM(self->presentation); + AcseConnection_destroy(self->acseConnection); + GLOBAL_FREEMEM(self->acseConnection); - AcseIndication aIndication; - AcseConnection acseConnection; + GLOBAL_FREEMEM(self->cotpReadBuf); + GLOBAL_FREEMEM(self->cotpWriteBuf); - ByteBuffer receiveBuffer; + GLOBAL_FREEMEM(self->cotpConnection); - self->cotpConnection = (CotpConnection*) calloc(1, sizeof(CotpConnection)); - CotpConnection_init(self->cotpConnection, self->socket, &receiveBuffer); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->conMutex); +#endif - self->session = (IsoSession*) calloc(1, sizeof(IsoSession)); - IsoSession_init(self->session); + GLOBAL_FREEMEM(self->receiveBuffer); + GLOBAL_FREEMEM(self->sendBuffer); + GLOBAL_FREEMEM(self->clientAddress); + IsoServer isoServer = self->isoServer; + GLOBAL_FREEMEM(self); + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: connection %p closed\n", self); - self->presentation = (IsoPresentation*) calloc(1, sizeof(IsoPresentation)); - IsoPresentation_init(self->presentation); + private_IsoServer_decreaseConnectionCounter(isoServer); +} - AcseConnection_init(&acseConnection, IsoServer_getAuthenticator(self->isoServer), - IsoServer_getAuthenticatorParameter(self->isoServer)); +void +IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles) +{ + Handleset_addSocket(handles, self->socket); +} - while (self->msgRcvdHandlerParameter == NULL) - Thread_sleep(1); +void +IsoConnection_handleTcpConnection(IsoConnection self) +{ + assert(self->msgRcvdHandler != NULL); - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress); + TpktState tpktState = CotpConnection_readToTpktBuffer(self->cotpConnection); - while (self->state == ISO_CON_STATE_RUNNING) { - ByteBuffer_wrap(&receiveBuffer, self->receiveBuffer, 0, RECEIVE_BUF_SIZE); + if (tpktState == TPKT_ERROR) + self->state = ISO_CON_STATE_STOPPED; - cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + if (tpktState != TPKT_PACKET_COMPLETE) + return; - switch (cotpIndication) { - case CONNECT_INDICATION: - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: COTP connection indication\n"); + CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); + + switch (cotpIndication) { + case COTP_MORE_FRAGMENTS_FOLLOW: + return; + case COTP_CONNECT_INDICATION: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: COTP connection indication\n"); - Semaphore_wait(self->conMutex); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->conMutex); +#endif - CotpConnection_sendConnectionResponseMessage(self->cotpConnection); + CotpConnection_sendConnectionResponseMessage(self->cotpConnection); - Semaphore_post(self->conMutex); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->conMutex); +#endif - break; - case DATA_INDICATION: - { - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: COTP data indication\n"); + break; + case COTP_DATA_INDICATION: + { + ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection); - ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection); + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: COTP data indication (payload size = %i)\n", cotpPayload->size); - sIndication = IsoSession_parseMessage(self->session, cotpPayload); + IsoSessionIndication sIndication = IsoSession_parseMessage(self->session, cotpPayload); - ByteBuffer* sessionUserData = IsoSession_getUserData(self->session); + ByteBuffer* sessionUserData = IsoSession_getUserData(self->session); - switch (sIndication) { - case SESSION_CONNECT: + switch (sIndication) { + case SESSION_CONNECT: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session connect indication\n"); + + if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) { if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: session connect indication\n"); + printf("ISO_SERVER: iso_connection: presentation ok\n"); - if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) { - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: presentation ok\n"); + ByteBuffer* acseBuffer = &(self->presentation->nextPayload); - ByteBuffer* acseBuffer = &(self->presentation->nextPayload); + AcseIndication aIndication = AcseConnection_parseMessage(self->acseConnection, acseBuffer); - aIndication = AcseConnection_parseMessage(&acseConnection, acseBuffer); + if (aIndication == ACSE_ASSOCIATE) { - self->securityToken = acseConnection.securityToken; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->conMutex); +#endif - if (aIndication == ACSE_ASSOCIATE) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: cotp_server: acse associate\n"); - Semaphore_wait(self->conMutex); + ByteBuffer mmsRequest; - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: cotp_server: acse associate\n"); + ByteBuffer_wrap(&mmsRequest, self->acseConnection->userDataBuffer, + self->acseConnection->userDataBufferSize, self->acseConnection->userDataBufferSize); + ByteBuffer mmsResponseBuffer; /* new */ - ByteBuffer mmsRequest; + ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); - ByteBuffer_wrap(&mmsRequest, acseConnection.userDataBuffer, - acseConnection.userDataBufferSize, acseConnection.userDataBufferSize); - ByteBuffer mmsResponseBuffer; /* new */ + if (self->msgRcvdHandler != NULL) { - ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = true; +#endif self->msgRcvdHandler(self->msgRcvdHandlerParameter, &mmsRequest, &mmsResponseBuffer); - struct sBufferChain mmsBufferPartStruct; - BufferChain mmsBufferPart = &mmsBufferPartStruct; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = false; +#endif + } - BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL, - self->sendBuffer); + struct sBufferChain mmsBufferPartStruct; + BufferChain mmsBufferPart = &mmsBufferPartStruct; - if (mmsResponseBuffer.size > 0) { - if (DEBUG_ISO_SERVER) - printf("iso_connection: application payload size: %i\n", - mmsResponseBuffer.size); + BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL, + self->sendBuffer); - struct sBufferChain acseBufferPartStruct; - BufferChain acseBufferPart = &acseBufferPartStruct; + if (mmsResponseBuffer.size > 0) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: application payload size: %i\n", + mmsResponseBuffer.size); - acseBufferPart->buffer = self->sendBuffer + mmsBufferPart->length; - acseBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length; + struct sBufferChain acseBufferPartStruct; + BufferChain acseBufferPart = &acseBufferPartStruct; - AcseConnection_createAssociateResponseMessage(&acseConnection, - ACSE_RESULT_ACCEPT, acseBufferPart, mmsBufferPart); + acseBufferPart->buffer = self->sendBuffer + mmsBufferPart->length; + acseBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length; - struct sBufferChain presentationBufferPartStruct; - BufferChain presentationBufferPart = &presentationBufferPartStruct; + AcseConnection_createAssociateResponseMessage(self->acseConnection, + ACSE_RESULT_ACCEPT, acseBufferPart, mmsBufferPart); - presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length; - presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length; + struct sBufferChain presentationBufferPartStruct; + BufferChain presentationBufferPart = &presentationBufferPartStruct; - IsoPresentation_createCpaMessage(self->presentation, presentationBufferPart, - acseBufferPart); + presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length; + presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length; - struct sBufferChain sessionBufferPartStruct; - BufferChain sessionBufferPart = &sessionBufferPartStruct; - sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; - sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; + IsoPresentation_createCpaMessage(self->presentation, presentationBufferPart, + acseBufferPart); - IsoSession_createAcceptSpdu(self->session, sessionBufferPart, presentationBufferPart); + struct sBufferChain sessionBufferPartStruct; + BufferChain sessionBufferPart = &sessionBufferPartStruct; + sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; + sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; - CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); - } - else { - if (DEBUG_ISO_SERVER) - printf( - "ISO_SERVER: iso_connection: association error. No response from application!\n"); - } + IsoSession_createAcceptSpdu(self->session, sessionBufferPart, presentationBufferPart); - Semaphore_post(self->conMutex); + CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); } else { if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: acse association failed\n"); - self->state = ISO_CON_STATE_STOPPED; + printf("ISO_SERVER: iso_connection: association error. No response from application!\n"); } +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->conMutex); +#endif } - break; - case SESSION_DATA: - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: session data indication\n"); - - if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) { + else { if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: cotp_server: presentation error\n"); + printf("ISO_SERVER: iso_connection: acse association failed\n"); self->state = ISO_CON_STATE_STOPPED; - break; } - if (self->presentation->nextContextId == self->presentation->mmsContextId) { - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: mms message\n"); - - ByteBuffer* mmsRequest = &(self->presentation->nextPayload); - - ByteBuffer mmsResponseBuffer; - - IsoServer_userLock(self->isoServer); - Semaphore_wait(self->conMutex); - - ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); + } + break; + case SESSION_DATA: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session data indication\n"); - self->msgRcvdHandler(self->msgRcvdHandlerParameter, - mmsRequest, &mmsResponseBuffer); + if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: presentation layer error\n"); + self->state = ISO_CON_STATE_STOPPED; + break; + } - if (mmsResponseBuffer.size > 0) { + if (self->presentation->nextContextId == self->presentation->mmsContextId) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: mms message\n"); + ByteBuffer* mmsRequest = &(self->presentation->nextPayload); - struct sBufferChain mmsBufferPartStruct; - BufferChain mmsBufferPart = &mmsBufferPartStruct; + ByteBuffer mmsResponseBuffer; - BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, - mmsResponseBuffer.size, NULL, self->sendBuffer); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + IsoServer_userLock(self->isoServer); + Semaphore_wait(self->conMutex); +#endif - struct sBufferChain presentationBufferPartStruct; - BufferChain presentationBufferPart = &presentationBufferPartStruct; - presentationBufferPart->buffer = self->sendBuffer + mmsBufferPart->length; - presentationBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length; + ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE); - IsoPresentation_createUserData(self->presentation, - presentationBufferPart, mmsBufferPart); + if (self->msgRcvdHandler != NULL) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = true; +#endif - struct sBufferChain sessionBufferPartStruct; - BufferChain sessionBufferPart = &sessionBufferPartStruct; - sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; - sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; - - IsoSession_createDataSpdu(self->session, sessionBufferPart, presentationBufferPart); - - CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); - } + self->msgRcvdHandler(self->msgRcvdHandlerParameter, + mmsRequest, &mmsResponseBuffer); - Semaphore_post(self->conMutex); - IsoServer_userUnlock(self->isoServer); - } - else { - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: unknown presentation layer context!"); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = false; +#endif } - break; - - case SESSION_FINISH: - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: session finish indication\n"); - - if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) { - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: iso_connection: presentation ok\n"); + /* send a response if required */ + if (mmsResponseBuffer.size > 0) { - struct sBufferChain acseBufferPartStruct; - BufferChain acseBufferPart = &acseBufferPartStruct; - acseBufferPart->buffer = self->sendBuffer; - acseBufferPart->partMaxLength = SEND_BUF_SIZE; + struct sBufferChain mmsBufferPartStruct; + BufferChain mmsBufferPart = &mmsBufferPartStruct; - AcseConnection_createReleaseResponseMessage(&acseConnection, acseBufferPart); + BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, + mmsResponseBuffer.size, NULL, self->sendBuffer); struct sBufferChain presentationBufferPartStruct; BufferChain presentationBufferPart = &presentationBufferPartStruct; - presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length; - presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length; + presentationBufferPart->buffer = self->sendBuffer + mmsBufferPart->length; + presentationBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length; - IsoPresentation_createUserDataACSE(self->presentation, presentationBufferPart, acseBufferPart); + IsoPresentation_createUserData(self->presentation, + presentationBufferPart, mmsBufferPart); struct sBufferChain sessionBufferPartStruct; BufferChain sessionBufferPart = &sessionBufferPartStruct; sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; - IsoSession_createDisconnectSpdu(self->session, sessionBufferPart, presentationBufferPart); + IsoSession_createDataSpdu(self->session, sessionBufferPart, presentationBufferPart); CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); } - self->state = ISO_CON_STATE_STOPPED; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->conMutex); + IsoServer_userUnlock(self->isoServer); +#endif + } + else { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: unknown presentation layer context!"); + } - break; + break; - case SESSION_ABORT: - self->state = ISO_CON_STATE_STOPPED; - break; + case SESSION_FINISH: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session finish indication\n"); - case SESSION_ERROR: - self->state = ISO_CON_STATE_STOPPED; - break; + if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: presentation ok\n"); - default: /* illegal state */ - self->state = ISO_CON_STATE_STOPPED; - break; - } - } - break; - case ERROR: - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: Connection closed\n"); - self->state = ISO_CON_STATE_STOPPED; - break; - default: - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: COTP Unknown Indication: %i\n", cotpIndication); - self->state = ISO_CON_STATE_STOPPED; - break; - } - } + struct sBufferChain acseBufferPartStruct; + BufferChain acseBufferPart = &acseBufferPartStruct; + acseBufferPart->buffer = self->sendBuffer; + acseBufferPart->partMaxLength = SEND_BUF_SIZE; - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: Connection handling loop finished --> close transport connection\n"); + AcseConnection_createReleaseResponseMessage(self->acseConnection, acseBufferPart); - IsoServer_closeConnection(self->isoServer, self); + struct sBufferChain presentationBufferPartStruct; + BufferChain presentationBufferPart = &presentationBufferPartStruct; + presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length; + presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length; - if (self->socket != NULL) - Socket_destroy(self->socket); + IsoPresentation_createUserDataACSE(self->presentation, presentationBufferPart, acseBufferPart); - free(self->session); - free(self->presentation); + struct sBufferChain sessionBufferPartStruct; + BufferChain sessionBufferPart = &sessionBufferPartStruct; + sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length; + sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length; - AcseConnection_destroy(&acseConnection); + IsoSession_createDisconnectSpdu(self->session, sessionBufferPart, presentationBufferPart); - CotpConnection_destroy(self->cotpConnection); - free(self->cotpConnection); + CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart); + } - Semaphore_destroy(self->conMutex); + self->state = ISO_CON_STATE_STOPPED; - free(self->receiveBuffer); - free(self->sendBuffer); - free(self->clientAddress); + break; - IsoServer isoServer = self->isoServer; + case SESSION_ABORT: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session abort indication\n"); + self->state = ISO_CON_STATE_STOPPED; + break; - free(self); + case SESSION_ERROR: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session error indication\n"); + self->state = ISO_CON_STATE_STOPPED; + break; - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: connection %p closed\n", self); + default: /* illegal state */ + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: iso_connection: session illegal state\n"); - private_IsoServer_decreaseConnectionCounter(isoServer); + self->state = ISO_CON_STATE_STOPPED; + break; + } + + CotpConnection_resetPayload(self->cotpConnection); + } + break; + case COTP_ERROR: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: Connection closed\n"); + self->state = ISO_CON_STATE_STOPPED; + break; + default: + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: COTP unknown indication: %i\n", cotpIndication); + self->state = ISO_CON_STATE_STOPPED; + break; + } } +#if (CONFIG_MMS_SINGLE_THREADED == 0) +static void +handleTcpConnection(void* parameter) +{ + IsoConnection self = (IsoConnection) parameter; + + while(self->state == ISO_CON_STATE_RUNNING) { + IsoConnection_handleTcpConnection(self); + Thread_sleep(1); + } + + finalizeIsoConnection(self); +} +#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */ + IsoConnection IsoConnection_create(Socket socket, IsoServer isoServer) { - IsoConnection self = (IsoConnection) calloc(1, sizeof(struct sIsoConnection)); + IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection)); self->socket = socket; - self->receiveBuffer = (uint8_t*) malloc(RECEIVE_BUF_SIZE); - self->sendBuffer = (uint8_t*) malloc(SEND_BUF_SIZE); + self->receiveBuffer = (uint8_t*) GLOBAL_MALLOC(RECEIVE_BUF_SIZE); + self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(SEND_BUF_SIZE); self->msgRcvdHandler = NULL; self->msgRcvdHandlerParameter = NULL; self->isoServer = isoServer; self->state = ISO_CON_STATE_RUNNING; self->clientAddress = Socket_getPeerAddress(self->socket); - self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, true); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->isInsideCallback = false; self->conMutex = Semaphore_create(1); +#endif - Thread_start(self->thread); + ByteBuffer_wrap(&(self->rcvBuffer), self->receiveBuffer, 0, RECEIVE_BUF_SIZE); + + self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + ByteBuffer_wrap(&(self->cotpReadBuffer), self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + ByteBuffer_wrap(&(self->cotpWriteBuffer), self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE); + + self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection)); + CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer)); + + self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession)); + IsoSession_init(self->session); + + self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation)); + IsoPresentation_init(self->presentation); + + self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection)); + AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer), + IsoServer_getAuthenticatorParameter(self->isoServer)); if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: new iso connection thread started\n"); + printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress); + +#if (CONFIG_MMS_SINGLE_THREADED == 0) +#if (CONFIG_MMS_THREADLESS_STACK == 0) + self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, true); + + Thread_start(self->thread); +#endif +#endif return self; } +void +IsoConnection_destroy(IsoConnection self) +{ + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: destroy called for IsoConnection.\n"); + + finalizeIsoConnection(self); +} + char* IsoConnection_getPeerAddress(IsoConnection self) { @@ -416,8 +512,10 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerM return; } - if (!handlerMode) +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->isInsideCallback == false) Semaphore_wait(self->conMutex); +#endif struct sBufferChain payloadBufferStruct; BufferChain payloadBuffer = &payloadBufferStruct; @@ -446,14 +544,16 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerM indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer); if (DEBUG_ISO_SERVER) { - if (indication != OK) + if (indication != COTP_OK) printf("ISO_SERVER: IsoConnection_sendMessage failed!\n"); else printf("ISO_SERVER: IsoConnection_sendMessage success!\n"); } - if (!handlerMode) +#if (CONFIG_MMS_THREADLESS_STACK != 1) + if (self->isInsideCallback == false) Semaphore_post(self->conMutex); +#endif } void @@ -479,6 +579,14 @@ IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler void* IsoConnection_getSecurityToken(IsoConnection self) { - return self->securityToken; + return self->acseConnection->securityToken; } +bool +IsoConnection_isRunning(IsoConnection self) +{ + if (self->state == ISO_CON_STATE_RUNNING) + return true; + else + return false; +} diff --git a/src/mms/iso_server/iso_server.c b/src/mms/iso_server/iso_server.c index dcb7e445..7bdbbba1 100644 --- a/src/mms/iso_server/iso_server.c +++ b/src/mms/iso_server/iso_server.c @@ -35,7 +35,7 @@ #include "mms_server_connection.h" -#include "thread.h" +#include "hal_thread.h" #include "iso_server.h" @@ -57,23 +57,47 @@ struct sIsoServer { AcseAuthenticator authenticator; void* authenticatorParameter; +#if (CONFIG_MMS_THREADLESS_STACK != 1) Thread serverThread; +#endif + Socket serverSocket; int tcpPort; char* localIpAddress; #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) LinkedList openClientConnections; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore openClientConnectionsMutex; /* mutex for openClientConnections list */ +#endif + #else IsoConnection* openClientConnections; -#endif +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore userLock; Semaphore connectionCounterMutex; +#endif int connectionCounter; }; +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) +static inline void +lockClientConnections(IsoServer self) +{ + Semaphore_wait(self->openClientConnectionsMutex); +} + +static inline void +unlockClientConnections(IsoServer self) +{ + Semaphore_post(self->openClientConnectionsMutex); +} +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + static void addClientConnection(IsoServer self, IsoConnection connection) { @@ -86,6 +110,10 @@ addClientConnection(IsoServer self, IsoConnection connection) for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { if (self->openClientConnections[i] == NULL) { self->openClientConnections[i] = connection; + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: added connection (%p) index:%i\n", connection, i); + break; } } @@ -96,17 +124,37 @@ static void removeClientConnection(IsoServer self, IsoConnection connection) { #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + + +#if (CONFIG_MMS_SINGLE_THREADED == 0) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + LinkedList_remove(self->openClientConnections, connection); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + +#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */ + + #else int i; for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { if (self->openClientConnections[i] == connection) { + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: removed connection (%p) index:%i\n", connection, i); + self->openClientConnections[i] = NULL; break; } } -#endif +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ } static void @@ -114,14 +162,35 @@ closeAllOpenClientConnections(IsoServer self) { #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + LinkedList openConnection = LinkedList_getNext(self->openClientConnections); while (openConnection != NULL) { IsoConnection isoConnection = (IsoConnection) openConnection->data; IsoConnection_close(isoConnection); +#if (CONFIG_MMS_SINGLE_THREADED == 1) + /* if CONFIG_MMS_SINGLE_THREADED == 0 connection instance will be destroyed by connection thread. */ + IsoConnection_destroy(isoConnection); +#endif + openConnection = LinkedList_getNext(openConnection); } + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + LinkedList_destroyStatic(self->openClientConnections); + self->openClientConnections = NULL; +#endif + + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + #else int i; @@ -130,27 +199,78 @@ closeAllOpenClientConnections(IsoServer self) IsoConnection_close(self->openClientConnections[i]); - break; +#if (CONFIG_MMS_SINGLE_THREADED == 1) + /* if CONFIG_MMS_SINGLE_THREADED == 0 connection instance will be destroyed by connection thread. */ + IsoConnection_destroy(self->openClientConnections[i]); +#endif + } } #endif } static void -isoServerThread(void* isoServerParam) +handleClientConnections(IsoServer self) { - IsoServer self = (IsoServer) isoServerParam; +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: isoServerThread %p started\n", &isoServerParam); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif - Socket connectionSocket; + LinkedList openConnection = LinkedList_getNext(self->openClientConnections); + LinkedList lastConnection = self->openClientConnections; + + while (openConnection != NULL) { + IsoConnection isoConnection = (IsoConnection) openConnection->data; + if (IsoConnection_isRunning(isoConnection)) + IsoConnection_handleTcpConnection(isoConnection); + else { + IsoConnection_destroy(isoConnection); + + lastConnection->next = openConnection->next; + + GLOBAL_FREEMEM(openConnection); + } + + openConnection = LinkedList_getNext(openConnection); + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif + +#else + + + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] != NULL) { + if (IsoConnection_isRunning(self->openClientConnections[i])) { + + IsoConnection_handleTcpConnection(self->openClientConnections[i]); + } + else { + IsoConnection_destroy(self->openClientConnections[i]); + + self->openClientConnections[i] = NULL; + } + + } + } +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ +} + +static bool +setupIsoServer(IsoServer self) +{ self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort); if (self->serverSocket == NULL) { self->state = ISO_SVR_STATE_ERROR; - goto cleanUp; + return false; } ServerSocket_setBacklog((ServerSocket) self->serverSocket, BACKLOG); @@ -159,36 +279,113 @@ isoServerThread(void* isoServerParam) self->state = ISO_SVR_STATE_RUNNING; - while (self->state == ISO_SVR_STATE_RUNNING) - { +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: server is limited to %i client connections.\n", (int) CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS); +#endif - if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) == NULL) { - break; - } - else { + return true; +} + + +#if (CONFIG_MMS_THREADLESS_STACK == 0) +// used by single and multi-threaded versions +static void +handleIsoConnections(IsoServer self) +{ + Socket connectionSocket; + + if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) { #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) - if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) { - if (DEBUG_ISO_SERVER) - printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); + if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); - Socket_destroy(connectionSocket); - continue; - } + Socket_destroy(connectionSocket); + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + handleClientConnections(self); #endif - IsoConnection isoConnection = IsoConnection_create(connectionSocket, self); + return; + } +#endif - private_IsoServer_increaseConnectionCounter(self); + IsoConnection isoConnection = IsoConnection_create(connectionSocket, self); - addClientConnection(self, isoConnection); + private_IsoServer_increaseConnectionCounter(self); + addClientConnection(self, isoConnection); - self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter, - isoConnection); + self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter, + isoConnection); + } + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + handleClientConnections(self); +#endif +} +#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */ + +// used by non-threaded version +static void +handleIsoConnectionsThreadless(IsoServer self) +{ + Socket connectionSocket; + + if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) { + +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) + if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n"); + + Socket_destroy(connectionSocket); + + handleClientConnections(self); + + return; } +#endif + + IsoConnection isoConnection = IsoConnection_create(connectionSocket, self); + + private_IsoServer_increaseConnectionCounter(self); + + addClientConnection(self, isoConnection); + + self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter, + isoConnection); + + } + + handleClientConnections(self); +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +// only required for multi-threaded server! +static void +isoServerThread(void* isoServerParam) +{ + IsoServer self = (IsoServer) isoServerParam; + + if (!setupIsoServer(self)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: starting server failed!\n"); + + goto cleanUp; + } + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: isoServerThread %p started\n", &isoServerParam); + while (self->state == ISO_SVR_STATE_RUNNING) + { + handleIsoConnections(self); + + Thread_sleep(1); } self->state = ISO_SVR_STATE_STOPPED; @@ -200,11 +397,12 @@ isoServerThread(void* isoServerParam) printf("ISO_SERVER: isoServerThread %p stopped\n", &isoServerParam); } +#endif IsoServer IsoServer_create() { - IsoServer self = (IsoServer) calloc(1, sizeof(struct sIsoServer)); + IsoServer self = (IsoServer) GLOBAL_CALLOC(1, sizeof(struct sIsoServer)); self->state = ISO_SVR_STATE_IDLE; self->tcpPort = TCP_PORT; @@ -213,10 +411,17 @@ IsoServer_create() self->openClientConnections = LinkedList_create(); #else self->openClientConnections = (IsoConnection*) - calloc(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS, sizeof(IsoConnection)); + GLOBAL_CALLOC(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS, sizeof(IsoConnection)); #endif +#if (CONFIG_MMS_THREADLESS_STACK != 1) self->connectionCounterMutex = Semaphore_create(1); +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + self->openClientConnectionsMutex = Semaphore_create(1); +#endif + +#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */ + self->connectionCounter = 0; return self; @@ -259,6 +464,7 @@ IsoServer_getAuthenticatorParameter(IsoServer self) return self->authenticatorParameter; } +#if (CONFIG_MMS_THREADLESS_STACK != 1) void IsoServer_startListening(IsoServer self) { @@ -266,22 +472,132 @@ IsoServer_startListening(IsoServer self) Thread_start(self->serverThread); + /* wait until server is up */ while (self->state == ISO_SVR_STATE_IDLE) Thread_sleep(1); if (DEBUG_ISO_SERVER) printf("ISO_SERVER: new iso server thread started\n"); } +#endif void -IsoServer_stopListening(IsoServer self) +IsoServer_startListeningThreadless(IsoServer self) { - self->state = ISO_SVR_STATE_STOPPED; + if (!setupIsoServer(self)) { + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: starting server failed!\n"); + + self->serverSocket = NULL; + } + else { + self->state = ISO_SVR_STATE_RUNNING; + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: new iso server (threadless) started\n"); + } +} + +int +IsoServer_waitReady(IsoServer self, unsigned int timeoutMs) +{ + int result; + + if (self->state == ISO_SVR_STATE_RUNNING) { + HandleSet handles; + + handles = Handleset_new(); + if (handles != NULL) { +#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); +#endif + + LinkedList openConnection = LinkedList_getNext(self->openClientConnections); + LinkedList lastConnection = self->openClientConnections; + + while (openConnection != NULL) { + IsoConnection isoConnection = (IsoConnection) openConnection->data; + + if (IsoConnection_isRunning(isoConnection)) { + IsoConnection_addHandleSet(isoConnection, handles); + openConnection = LinkedList_getNext(openConnection); + } else { + IsoConnection_destroy(isoConnection); + lastConnection->next = openConnection->next; + free(openConnection); + openConnection = lastConnection->next; + } + + lastConnection = lastConnection->next; + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + unlockClientConnections(self); +#endif +#else + int i; + + for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) { + if (self->openClientConnections[i] != NULL) { + if (IsoConnection_isRunning(self->openClientConnections[i])) { + IsoConnection_addHandleSet(self->openClientConnections[i], handles); + } else { + IsoConnection_destroy(self->openClientConnections[i]); + self->openClientConnections[i] = NULL; + } + } + } +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + Handleset_addSocket(handles, self->serverSocket); + result = Handleset_waitReady(handles, timeoutMs); + Handleset_destroy(handles); + } else { + result = -1; + } + } else { + result = -1; + } + + return result; +} + + +void +IsoServer_processIncomingMessages(IsoServer self) +{ + if (self->state == ISO_SVR_STATE_RUNNING) + handleIsoConnectionsThreadless(self); +} + +static void +stopListening(IsoServer self) +{ + self->state = ISO_SVR_STATE_STOPPED; if (self->serverSocket != NULL) { ServerSocket_destroy((ServerSocket) self->serverSocket); self->serverSocket = NULL; } +} + +void +IsoServer_stopListeningThreadless(IsoServer self) +{ + stopListening(self); + + closeAllOpenClientConnections(self); + + if (DEBUG_ISO_SERVER) + printf("ISO_SERVER: IsoServer_stopListeningThreadless finished!\n"); +} + +#if (CONFIG_MMS_THREADLESS_STACK != 1) +void +IsoServer_stopListening(IsoServer self) +{ + stopListening(self); if (self->serverThread != NULL) Thread_destroy(self->serverThread); @@ -295,6 +611,7 @@ IsoServer_stopListening(IsoServer self) if (DEBUG_ISO_SERVER) printf("ISO_SERVER: IsoServer_stopListening finished!\n"); } +#endif void IsoServer_closeConnection(IsoServer self, IsoConnection isoConnection) @@ -318,40 +635,69 @@ IsoServer_setConnectionHandler(IsoServer self, ConnectionIndicationHandler handl void IsoServer_destroy(IsoServer self) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) if (self->state == ISO_SVR_STATE_RUNNING) IsoServer_stopListening(self); +#endif #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) - LinkedList_destroy(self->openClientConnections); + +#if (CONFIG_MMS_SINGLE_THREADED == 1) + if (self->openClientConnections != NULL) + LinkedList_destroy(self->openClientConnections); #else - free(self->openClientConnections); + if (self->openClientConnections != NULL) + LinkedList_destroyStatic(self->openClientConnections); +#endif /* (CONFIG_MMS_SINGLE_THREADED == 1) */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + lockClientConnections(self); + Semaphore_destroy(self->openClientConnectionsMutex); #endif +#else + GLOBAL_FREEMEM(self->openClientConnections); +#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */ + +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_destroy(self->connectionCounterMutex); +#endif - free(self); + GLOBAL_FREEMEM(self); } void private_IsoServer_increaseConnectionCounter(IsoServer self) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->connectionCounterMutex); +#endif + self->connectionCounter++; if (DEBUG_ISO_SERVER) printf("IsoServer: increase connection counter to %i!\n", self->connectionCounter); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->connectionCounterMutex); +#endif } void private_IsoServer_decreaseConnectionCounter(IsoServer self) { - +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->connectionCounterMutex); +#endif + self->connectionCounter--; if (DEBUG_ISO_SERVER) printf("IsoServer: decrease connection counter to %i!\n", self->connectionCounter); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->connectionCounterMutex); +#endif } int @@ -359,13 +705,20 @@ private_IsoServer_getConnectionCounter(IsoServer self) { int connectionCounter; +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->connectionCounterMutex); +#endif + connectionCounter = self->connectionCounter; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->connectionCounterMutex); +#endif return connectionCounter; } +#if (CONFIG_MMS_THREADLESS_STACK != 1) void IsoServer_setUserLock(IsoServer self, Semaphore userLock) { @@ -385,3 +738,4 @@ IsoServer_userUnlock(IsoServer self) if (self->userLock != NULL) Semaphore_post(self->userLock); } +#endif diff --git a/src/mms/iso_session/iso_session.c b/src/mms/iso_session/iso_session.c index 0b3b1614..8e0fe0ca 100644 --- a/src/mms/iso_session/iso_session.c +++ b/src/mms/iso_session/iso_session.c @@ -127,12 +127,13 @@ parseSessionHeaderParameters(IsoSession* session, ByteBuffer* message, int param case 1: /* Connection Identifier */ if (DEBUG_SESSION) printf("SESSION: PGI - connection identifier\n"); - printf("TODO: PGI not implemented!"); + offset += parameterLength; break; case 5: /* Connection/Accept Item */ if (DEBUG_SESSION) printf("SESSION: PGI - Connection/Accept Item\n"); + int connectAcceptLen; connectAcceptLen = parseAcceptParameters(session, message, offset, parameterLength); diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index aa3b2b60..d98c9e2f 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -95,7 +95,7 @@ preparePacketBuffer(SampledValuesPublisher self, CommParameters* parameters, cha else self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr); - self->buffer = (uint8_t*) malloc(SV_MAX_MESSAGE_SIZE); + self->buffer = (uint8_t*) GLOBAL_MALLOC(SV_MAX_MESSAGE_SIZE); memcpy(self->buffer, dstAddr, 6); memcpy(self->buffer + 6, srcAddr, 6); diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def index b550d1dd..a531d9ab 100644 --- a/src/vs/libiec61850-wo-goose.def +++ b/src/vs/libiec61850-wo-goose.def @@ -93,6 +93,7 @@ EXPORTS ControlObjectClient_select @220 ControlObjectClient_selectWithValue @221 ControlObjectClient_setLastApplError @222 + ControlObjectClient_setCommandTerminationHandler DataAttribute_create @273 DataObject_create @274 DataObject_hasFCData @275 @@ -378,6 +379,8 @@ EXPORTS MmsValue_toUint32 @774 MmsValue_toUnixTimestamp @775 MmsValue_update @776 + MmsValue_getBitStringAsIntegerBigEndian + MmsValue_setBitStringFromIntegerBigEndian MmsVariableAccessSpecification_create @777 MmsVariableAccessSpecification_createAlternateAccess @778 MmsVariableAccessSpecification_destroy @779 @@ -390,6 +393,7 @@ EXPORTS MmsVariableSpecification_getSize @786 MmsVariableSpecification_getStructureElements @787 MmsVariableSpecification_getType @788 + MmsVariableSpecification_getNamedVariableRecursive ModelNode_getChild @789 ModelNode_getChildCount @790 ModelNode_getObjectReference @791 @@ -438,3 +442,32 @@ EXPORTS AcseAuthenticationParameter_destroy AcseAuthenticationParameter_setAuthMechanism AcseAuthenticationParameter_setPassword + IedServer_startThreadless + IedServer_processIncomingData + IedServer_performPeriodicTasks + IedServer_stopThreadless + Dbpos_fromMmsValue + Dbpos_toMmsValue + SettingGroupControlBlock_create + MmsConnection_setConnectTimeout + IedConnection_setConnectTimeout + MmsValue_newVisibleStringWithSize + MmsValue_newMmsStringWithSize + MmsValue_setInt8 + MmsValue_setInt16 + LogicalDevice_getSettingGroupControlBlock + IedServer_changeActiveSettingGroup + IedServer_setActiveSettingGroupChangedHandler + IedServer_disableGoosePublishing + IedServer_setEditSettingGroupChangedHandler + IedServer_setEditSettingGroupConfirmationHandler + IedConnection_getDataDirectoryByFC + IedServer_getActiveSettingGroup + ClientReport_hasSeqNum + ClientReport_getSeqNum + ClientReport_hasDataSetName + ClientReport_hasReasonForInclusion + ClientReport_hasConfRev + ClientReport_getConfRev + ClientReport_hasBufOvfl + ClientReport_hasDataReference diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def index 807393a8..2fc47403 100644 --- a/src/vs/libiec61850.def +++ b/src/vs/libiec61850.def @@ -91,8 +91,9 @@ EXPORTS ControlObjectClient_getObjectReference @218 ControlObjectClient_operate @219 ControlObjectClient_select @220 - ControlObjectClient_selectWithValue @221 + ControlObjectClient_selectWithValue @221MmsConnection_setConnectTimeout ControlObjectClient_setLastApplError @222 + ControlObjectClient_setCommandTerminationHandler DataAttribute_create @273 DataObject_create @274 DataObject_hasFCData @275 @@ -138,10 +139,7 @@ EXPORTS GooseSubscriber_isTest @347 GooseSubscriber_needsCommission @348 GooseSubscriber_setAppId @349 - GooseSubscriber_setInterfaceId @350 GooseSubscriber_setListener @351 - GooseSubscriber_subscribe @352 - GooseSubscriber_unsubscribe @353 Hal_getTimeInMs @354 IedConnection_abort @366 IedConnection_close @367 @@ -405,6 +403,8 @@ EXPORTS MmsValue_toUint32 @774 MmsValue_toUnixTimestamp @775 MmsValue_update @776 + MmsValue_getBitStringAsIntegerBigEndian + MmsValue_setBitStringFromIntegerBigEndian MmsVariableAccessSpecification_create @777 MmsVariableAccessSpecification_createAlternateAccess @778 MmsVariableAccessSpecification_destroy @779 @@ -417,6 +417,7 @@ EXPORTS MmsVariableSpecification_getSize @786 MmsVariableSpecification_getStructureElements @787 MmsVariableSpecification_getType @788 + MmsVariableSpecification_getNamedVariableRecursive ModelNode_getChild @789 ModelNode_getChildCount @790 ModelNode_getObjectReference @791 @@ -465,5 +466,32 @@ EXPORTS AcseAuthenticationParameter_destroy AcseAuthenticationParameter_setAuthMechanism AcseAuthenticationParameter_setPassword - - + IedServer_startThreadless + IedServer_processIncomingData + IedServer_performPeriodicTasks + IedServer_stopThreadless + Dbpos_fromMmsValue + Dbpos_toMmsValue + SettingGroupControlBlock_create + MmsConnection_setConnectTimeout + IedConnection_setConnectTimeout + MmsValue_newVisibleStringWithSize + MmsValue_newMmsStringWithSize + MmsValue_setInt8 + MmsValue_setInt16 + LogicalDevice_getSettingGroupControlBlock + IedServer_changeActiveSettingGroup + IedServer_setActiveSettingGroupChangedHandler + IedServer_disableGoosePublishing + IedServer_setEditSettingGroupChangedHandler + IedServer_setEditSettingGroupConfirmationHandler + IedConnection_getDataDirectoryByFC + IedServer_getActiveSettingGroup + ClientReport_hasSeqNum + ClientReport_getSeqNum + ClientReport_hasDataSetName + ClientReport_hasReasonForInclusion + ClientReport_hasConfRev + ClientReport_getConfRev + ClientReport_hasBufOvfl + ClientReport_hasDataReference diff --git a/tools/model_generator/genconfig.jar b/tools/model_generator/genconfig.jar index 9d65c0bc..51a60770 100644 Binary files a/tools/model_generator/genconfig.jar and b/tools/model_generator/genconfig.jar differ diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar index f04e74a0..84067d06 100644 Binary files a/tools/model_generator/genmodel.jar and b/tools/model_generator/genmodel.jar differ diff --git a/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java b/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java index 6fbc447a..bbc2fba4 100644 --- a/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java +++ b/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java @@ -23,11 +23,17 @@ package com.libiec61850.scl; * See COPYING file for the complete license text. */ +import java.util.LinkedList; + import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import com.libiec61850.scl.model.AttributeType; +import com.libiec61850.scl.model.DataModelValue; import com.libiec61850.scl.model.FunctionalConstraint; import com.libiec61850.scl.model.TriggerOptions; +import com.libiec61850.scl.types.IllegalValueException; +import com.libiec61850.scl.types.SclType; public class DataAttributeDefinition { @@ -38,8 +44,9 @@ public class DataAttributeDefinition { private FunctionalConstraint fc = null; private AttributeType attributeType = null; private TriggerOptions triggerOptions = null; + private DataModelValue value = null; - public DataAttributeDefinition(Node node) throws SclParserException { + public DataAttributeDefinition(Node node) throws SclParserException { this.name = ParserUtils.parseAttribute(node, "name"); this.bType = ParserUtils.parseAttribute(node, "bType"); this.type = ParserUtils.parseAttribute(node, "type"); @@ -89,6 +96,31 @@ public class DataAttributeDefinition { if (countStr != null) count = new Integer(countStr); + + if (this.bType != null) { + + NodeList elementNodes = node.getChildNodes(); + + if (elementNodes != null) { + + for (int i = 0; i < elementNodes.getLength(); i++) { + Node elementNode = elementNodes.item(i); + if (elementNode.getNodeName().equals("Val")) { + + String value = elementNode.getTextContent(); + + if (attributeType != AttributeType.ENUMERATED) + try { + this.value = new DataModelValue(attributeType, null, value); + } catch (IllegalValueException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } + } + } } public String getName() { @@ -115,6 +147,10 @@ public class DataAttributeDefinition { return count; } + public DataModelValue getValue() { + return value; + } + public TriggerOptions getTriggerOptions() { return this.triggerOptions; } diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java b/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java index 7318aa1d..573183f2 100644 --- a/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java @@ -47,6 +47,8 @@ public class DataAttribute implements DataModelNode { private SclType sclType = null; private TriggerOptions triggerOptions = null; + + private DataAttributeDefinition definition = null; public DataAttribute(DataAttributeDefinition daDefinition, TypeDeclarations typeDeclarations, FunctionalConstraint fc, DataModelNode parent) throws SclParserException { @@ -55,6 +57,7 @@ public class DataAttribute implements DataModelNode { this.type = daDefinition.getAttributeType(); this.count = daDefinition.getCount(); this.parent = parent; + this.definition = daDefinition; if (this.fc == null) this.fc = fc; @@ -163,6 +166,10 @@ public class DataAttribute implements DataModelNode { public TriggerOptions getTriggerOptions() { return this.triggerOptions; } + + public DataAttributeDefinition getDefinition() { + return this.definition; + } @Override public DataModelNode getParent() { diff --git a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java index fb35f5f3..8fa7c58c 100644 --- a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java +++ b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java @@ -51,7 +51,7 @@ public class LogicalNode implements DataModelNode { private List logs; private List settingGroupControlBlocks; - private LogicalDevice parentLogicalDevice; + private LogicalDevice parentLogicalDevice; public LogicalNode(Node lnNode, TypeDeclarations typeDeclarations, LogicalDevice parent) throws SclParserException { @@ -133,6 +133,9 @@ public class LogicalNode implements DataModelNode { List sgNodes = ParserUtils.getChildNodesWithTag(lnNode, "SettingControl"); + if ((this.lnClass.equals("LLN0") == false) && (sgNodes.size() > 0)) + throw new SclParserException(lnNode, "LN other than LN0 is not allowed to contain SettingControl"); + if (sgNodes.size() > 1) throw new SclParserException(lnNode, "LN contains more then one SettingControl"); @@ -257,6 +260,10 @@ public class LogicalNode implements DataModelNode { public List getGSEControlBlocks() { return gseControlBlocks; } + + public List getSettingGroupControlBlocks() { + return settingGroupControlBlocks; + } @Override public DataModelNode getChildByName(String childName) { diff --git a/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java b/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java index ed56dda3..928547c8 100644 --- a/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java +++ b/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java @@ -66,6 +66,7 @@ public class DataAttributeType extends SclType { subDataAttributes.add(dad); } + } } } diff --git a/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java b/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java index b818f225..3e0f3456 100644 --- a/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java +++ b/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java @@ -75,12 +75,22 @@ public class DataObjectType extends SclType { if (elementNode.getNodeName().equals("DA")) { DataAttributeDefinition dad = new DataAttributeDefinition(elementNode); + + DataAttributeDefinition otherDefinition = getDataAttributeByName(dad.getName()); + + if (otherDefinition != null) { + + if (otherDefinition.getFc() == dad.getFc()) + throw new SclParserException(xmlNode, + "DO type definition contains multiple elements of name \"" + + dad.getName() + "\""); + } - if ((getDataAttributeByName(dad.getName()) != null) || - (getDataObjectByName(dad.getName()) != null)) + if (getDataObjectByName(dad.getName()) != null) { throw new SclParserException(xmlNode, "DO type definition contains multiple elements of name \"" + dad.getName() + "\""); + } dataAttributes.add(dad); diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java index 9b5868f5..2fb76e4f 100644 --- a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java @@ -31,6 +31,7 @@ import java.io.InputStream; import java.io.PrintStream; import java.util.List; +import com.libiec61850.scl.DataAttributeDefinition; import com.libiec61850.scl.SclParser; import com.libiec61850.scl.SclParserException; import com.libiec61850.scl.communication.ConnectedAP; @@ -46,6 +47,7 @@ import com.libiec61850.scl.model.IED; import com.libiec61850.scl.model.LogicalDevice; import com.libiec61850.scl.model.LogicalNode; import com.libiec61850.scl.model.ReportControlBlock; +import com.libiec61850.scl.model.SettingControl; public class DynamicModelGenerator { @@ -82,7 +84,7 @@ public class DynamicModelGenerator { output.println("MODEL(" + ied.getName() + "){"); for (LogicalDevice logicalDevice : logicalDevices) { output.print("LD("); - output.print(ied.getName() + logicalDevice.getInst() + "){\n"); + output.print(logicalDevice.getInst() + "){\n"); exportLogicalNodes(output, logicalDevice); @@ -106,6 +108,11 @@ public class DynamicModelGenerator { } private void exportLogicalNode(PrintStream output, LogicalNode logicalNode) { + + for (SettingControl sgcb : logicalNode.getSettingGroupControlBlocks()) { + output.print("SG(" + sgcb.getActSG() + " " + sgcb.getNumOfSGs() + ")\n"); + } + for (DataObject dataObject : logicalNode.getDataObjects()) { output.print("DO(" + dataObject.getName() + " " + dataObject.getCount() + "){\n"); @@ -274,8 +281,12 @@ public class DynamicModelGenerator { output.print(")"); if (dataAttribute.isBasicAttribute()) { - DataModelValue value = dataAttribute.getValue(); - + DataModelValue value = dataAttribute.getValue(); + + /* if no value is given use default value for type if present */ + if (value == null) + value = dataAttribute.getDefinition().getValue(); + if (value != null) { switch (dataAttribute.getType()) { diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java index bd744a06..0c6afc0b 100644 --- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java @@ -44,6 +44,7 @@ import com.libiec61850.scl.model.DataAttribute; import com.libiec61850.scl.model.DataModelValue; import com.libiec61850.scl.model.DataObject; import com.libiec61850.scl.model.DataSet; +import com.libiec61850.scl.model.FunctionalConstraint; import com.libiec61850.scl.model.FunctionalConstraintData; import com.libiec61850.scl.model.GSEControl; import com.libiec61850.scl.model.IED; @@ -51,6 +52,7 @@ import com.libiec61850.scl.model.LogicalDevice; import com.libiec61850.scl.model.LogicalNode; import com.libiec61850.scl.model.ReportControlBlock; import com.libiec61850.scl.model.Server; +import com.libiec61850.scl.model.SettingControl; import com.libiec61850.scl.model.TriggerOptions; public class StaticModelGenerator { @@ -68,6 +70,10 @@ public class StaticModelGenerator { private StringBuffer gseControlBlocks; private List gseVariableNames; private int currentGseVariableNumber = 0; + + private StringBuffer settingGroupControlBlocks; + private List sgcbVariableNames; + private int currentSGCBVariableNumber = 0; private List dataSetNames; @@ -88,6 +94,9 @@ public class StaticModelGenerator { this.rcbVariableNames = new LinkedList(); this.gseControlBlocks = new StringBuffer(); this.gseVariableNames = new LinkedList(); + + this.settingGroupControlBlocks = new StringBuffer(); + this.sgcbVariableNames = new LinkedList(); SclParser sclParser = new SclParser(stream); @@ -195,15 +204,19 @@ public class StaticModelGenerator { } } - private String getLogicalDeviceName(LogicalDevice logicalDevice) { - String logicalDeviceName = logicalDevice.getLdName(); - - if (logicalDeviceName == null) - logicalDeviceName = ied.getName() + logicalDevice.getInst(); - - return logicalDeviceName; +// private String getLogicalDeviceName(LogicalDevice logicalDevice) { +// String logicalDeviceName = logicalDevice.getLdName(); +// +// if (logicalDeviceName == null) +// logicalDeviceName = ied.getName() + logicalDevice.getInst(); +// +// return logicalDeviceName; +// } + + private String getLogicalDeviceInst(LogicalDevice logicalDevice) { + return logicalDevice.getInst(); } - + private void printDeviceModelDefinitions() { printDataSets(); @@ -213,6 +226,8 @@ public class StaticModelGenerator { createReportVariableList(logicalDevices); createGooseVariableList(logicalDevices); + + createSettingControlsVariableList(logicalDevices); for (int i = 0; i < logicalDevices.size(); i++) { @@ -222,7 +237,7 @@ public class StaticModelGenerator { variablesList.add(ldName); - String logicalDeviceName = getLogicalDeviceName(logicalDevice); + String logicalDeviceName = getLogicalDeviceInst(logicalDevice); cOut.println("\nLogicalDevice " + ldName + " = {"); @@ -257,6 +272,11 @@ public class StaticModelGenerator { cOut.println("extern GSEControlBlock " + gcb + ";"); cOut.println(gseControlBlocks); + + for (String sgcb : sgcbVariableNames) + cOut.println("extern SettingGroupControlBlock " + sgcb + ";"); + + cOut.println(settingGroupControlBlocks); String firstLogicalDeviceName = logicalDevices.get(0).getInst(); cOut.println("\nIedModel iedModel = {"); @@ -277,6 +297,11 @@ public class StaticModelGenerator { cOut.println(" &" + gseVariableNames.get(0) + ","); else cOut.println(" NULL,"); + + if (sgcbVariableNames.size() > 0) + cOut.println(" &" + sgcbVariableNames.get(0) + ","); + else + cOut.println(" NULL,"); cOut.println(" initializeValues\n};"); } @@ -315,7 +340,12 @@ public class StaticModelGenerator { for (ReportControlBlock rcb : rcbs) { - for (int i = 0; i < rcb.getRptEna().getMaxInstances(); i++) { + int maxInstances = 1; + + if (rcb.getRptEna() != null) + maxInstances = rcb.getRptEna().getMaxInstances(); + + for (int i = 0; i < maxInstances; i++) { String rcbVariableName = "iedModel_" + ldName + "_" + ln.getName() + "_report" + rcbCount; rcbVariableNames.add(rcbVariableName); rcbCount++; @@ -325,6 +355,26 @@ public class StaticModelGenerator { } } } + + private void createSettingControlsVariableList(List logicalDevices) { + for (LogicalDevice ld : logicalDevices) { + List lnodes = ld.getLogicalNodes(); + + String ldName = ld.getInst(); + + for (LogicalNode ln : lnodes) { + List sgcbs = ln.getSettingGroupControlBlocks(); + + for (SettingControl sgcb : sgcbs) { + + String sgcbVariableName = "iedModel_" + ldName + "_" + ln.getName() + "_sgcb"; + + sgcbVariableNames.add(sgcbVariableName); + + } + } + } + } private void printLogicalNodeDefinitions(String ldName, List logicalNodes) { for (int i = 0; i < logicalNodes.size(); i++) { @@ -354,6 +404,8 @@ public class StaticModelGenerator { printReportControlBlocks(lnName, logicalNode); printGSEControlBlocks(ldName, lnName, logicalNode); + + printSettingControlBlock(lnName, logicalNode); } } @@ -412,6 +464,13 @@ public class StaticModelGenerator { DataAttribute dataAttribute = dataAttributes.get(i); String daName = doName + "_" + dataAttribute.getName(); + + if (dataAttribute.getFc() == FunctionalConstraint.SE) { + + if (daName.startsWith("iedModel_SE_") == false) + daName = daName.substring(0, 9) + "SE_" + daName.substring(9); + + } variablesList.add(daName); @@ -419,8 +478,18 @@ public class StaticModelGenerator { cOut.println(" DataAttributeModelType,"); cOut.println(" \"" + dataAttribute.getName() + "\","); cOut.println(" (ModelNode*) &" + doName + ","); - if (i < (dataAttributes.size() - 1)) - cOut.println(" (ModelNode*) &" + doName + "_" + dataAttributes.get(i + 1).getName() + ","); + if (i < (dataAttributes.size() - 1)) { + DataAttribute sibling = dataAttributes.get(i + 1); + + String siblingDoName = doName; + + if (sibling.getFc() == FunctionalConstraint.SE) { + if (siblingDoName.startsWith("iedModel_SE_") == false) + siblingDoName = siblingDoName.substring(0, 9) + "SE_" + siblingDoName.substring(9); + } + + cOut.println(" (ModelNode*) &" + siblingDoName + "_" + dataAttributes.get(i + 1).getName() + ","); + } else cOut.println(" NULL,"); if ((dataAttribute.getSubDataAttributes() != null) && (dataAttribute.getSubDataAttributes().size() > 0)) @@ -570,7 +639,13 @@ public class StaticModelGenerator { private void printDataAttributeForwardDeclarations(String doName, List dataAttributes) { for (DataAttribute dataAttribute : dataAttributes) { String daName = doName + "_" + dataAttribute.getName(); - + + if (dataAttribute.getFc() == FunctionalConstraint.SE) { + + if (daName.startsWith("iedModel_SE_") == false) + daName = daName.substring(0, 9) + "SE_" + daName.substring(9); + } + cOut.println("extern DataAttribute " + daName + ";"); hOut.println("extern DataAttribute " + daName + ";"); @@ -587,7 +662,7 @@ public class StaticModelGenerator { cOut.println(" * automatically generated from " + filename); cOut.println(" */"); cOut.println("#include "); - cOut.println("#include \"model.h\""); + cOut.println("#include \"iec61850_model.h\""); cOut.println(); } @@ -600,7 +675,7 @@ public class StaticModelGenerator { hOut.println("#ifndef STATIC_MODEL_H_"); hOut.println("#define STATIC_MODEL_H_\n"); hOut.println("#include "); - hOut.println("#include \"model.h\""); + hOut.println("#include \"iec61850_model.h\""); hOut.println(); } @@ -718,9 +793,37 @@ public class StaticModelGenerator { printReportControlBlockInstance(lnPrefix, rcb, "", reportNumber, reportsCount); reportNumber++; } - } - + } + + private void printSettingControlBlock(String lnPrefix, LogicalNode logicalNode) + { + List settingControls = logicalNode.getSettingGroupControlBlocks(); + + if (settingControls.size() > 0) { + System.out.println("print SGCB for " + lnPrefix); + + SettingControl sgcb = settingControls.get(0); + + String sgcbVariableName = lnPrefix + "_sgcb"; + + String sgcbString = "\nSettingGroupControlBlock " + sgcbVariableName + " = {"; + + sgcbString += "&" + lnPrefix + ", "; + + sgcbString += sgcb.getActSG() + ", " + sgcb.getNumOfSGs() + ", 0, false, 0, 0, "; + + if (currentSGCBVariableNumber < (sgcbVariableNames.size() - 1)) + sgcbString += "&" + sgcbVariableNames.get(currentGseVariableNumber + 1); + else + sgcbString += "NULL"; + + sgcbString += "};\n"; + + this.settingGroupControlBlocks.append(sgcbString); + + currentSGCBVariableNumber++; + } } private void printReportControlBlockInstance(String lnPrefix, ReportControlBlock rcb, String index, int reportNumber, int reportsCount) { @@ -798,8 +901,6 @@ public class StaticModelGenerator { rcbString += "NULL"; rcbString += "};\n"; - - System.out.println("RCB: " + rcbString); this.reportControlBlocks.append(rcbString); } @@ -873,7 +974,7 @@ public class StaticModelGenerator { String dataSetEntryName = dataSetVariableName + "_fcda" + fcdaCount; cOut.println("DataSetEntry " + dataSetEntryName + " = {"); - cOut.println(" \"" + ied.getName() + fcda.getLdInstance() + "\","); + cOut.println(" \"" + fcda.getLdInstance() + "\","); String mmsVariableName = ""; @@ -918,7 +1019,7 @@ public class StaticModelGenerator { String lnVariableName = "iedModel_" + logicalDevice.getInst() + "_" + logicalNode.getName(); - cOut.println(" \"" + ied.getName() + logicalDevice.getInst() + "\","); + cOut.println(" \"" + logicalDevice.getInst() + "\","); cOut.println(" \"" + logicalNode.getName() + "$" + dataSet.getName() + "\","); cOut.println(" " + dataSet.getFcda().size() + ","); cOut.println(" &" + dataSetVariableName + "_fcda0,");