Merge branch 'v1.6_develop' into v1.6_develop_329_GOOSE_signatures

v1.6_develop_329_GOOSE_signatures
Michael Zillgith 5 months ago
commit c7a4ef42df

@ -0,0 +1,192 @@
---
Language: Cpp
# BasedOnStyle: Microsoft
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: All
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: false
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: NoIndent
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

@ -0,0 +1,26 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'libiec61850'
dry-run: false
language: c
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'libiec61850'
fuzz-seconds: 300
dry-run: false
language: c
- name: Upload Crash
uses: actions/upload-artifact@v3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

3
.gitignore vendored

@ -1,2 +1,5 @@
build/
/Debug/
third_party/mbedtls
third_party/winpcap
third_party/sqlite

@ -1,8 +1,148 @@
Changes to version 1.5.1
Changes to version 1.6.0
------------------------
New features and improvements:
- Updated array handling (every array element is now a separate ModelNode instance)
- IED server: added additional callbacks to control external access to the data model (required to implement RBAC)
- IED server: implemented write access handler for array elements and components of array elements (LIB61850-437)
- IED server: new function IedServer_handleWriteAccessForDataObject (LIB61850-437)
- IED server: added function to get timestamp of received command (ControlAction_getT) (LIB61850-422)
- IED client: added function IedClientError_toString
- Java tools: Support for time stamp Val elements
- IedServer: added configuration options to IedServerConfig to make RCB elements read-only (LIB61850-404)
- .NET API: Added functions SetReportSetting and GetReportSetting to IedServerConfig (LIB61850-404)
- IED client: added functions IedConnection_setRCBValuesAsync and IedConnection_getRCBValuesAsync (LIB61850-334)
- TLS: TLS version 1.3 can be supported when mbedtls 3.6 is used when compiling the library (using mbedtls 2.28 is still possible)
- BETA: Support for R-GOOSE and R-SV
- BETA: SNTP client code
- IED server: extended config file format to better support arrays (LIB61850-415)
Other changes:
- Ethernet(Linux): Set to promisc mode by default
- removed legacy defines for report reasons (#449)
- removed legacy compatibility functions for SV subscriner ("SVClientaSDU_")
Fixed bugs and vulnerabilities:
- Vulnerability: fixed potential stack buffer overflow in MMS client identity service and other services (LIB61850-447)
- Vulnerability: ACSE: fixed out-of-bound read in parseAarqPdu function (LIB61850-441)(#512)
- Vulnerability: ACSE: fixed out-of-bound read in parseAarePdu function (LIB61850-442)(#513)
- Vulnerability: GOOSE receiver: added additional length and plausibility checks to fix (LIB6150-440)(#509)
- MmsValue_decodeMmsData: add support for empty visible-string, mms-string, and octet-string values (#506)
- MMS client: fixed - getNameList task can get stuck in while loop when message cannot be sent (LIB61850-347)
- fix: ssl renegotiation causing handshake failure (#494)
- GOOSE publisher: fixed - publisher parameters not set correctly (I6LLCV-76)
- fixed potential memory leak when GooseReceiver is immediately stopped after start (I6PLLCV-71)
- .NET API: fixed - crash when GetDataSetDirectoryAsync returns error (LIB61850-434)
- MMS server: fixed - server is sending data set response larger than negotiated MMS PDU size (LIB61850-435)
- fixed - potential race condition when using IedConnection_installReportHandler and IedConnection_uninstallReportHandler
- fixed - IEC 61580 server: dataset is not released when RCB.Datset is set to empty string by client (LIB61850-425)
- Vulnerability: MMS client: fixed - parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469)
- fixed DPC status bug in beaglebone demo
- IED cllient: fixed memory leak and memory handling problem in function IedConnection_readDataSetValuesAsync (LIB61850-439)
- IED server: fixed crash when client tries to write complete SGCB structure
Changes to version 1.5.3 (Dec 18, 2023)
---------------------------------------
New features and improvements:
- config file parser dynamically allocates linebuffer to allow multithreaded applications (#484)
- parse time values in model configuration file (LIB61850-426)
- config file generator: added missing code for GSEControl (LIB61850-418)
- Config file generator: support multiple access points for GOOSE and SMV control blocks (LIB61850-418)
- config file generator: added code to add SMVCBs to config files (LIB61850-67)
- IED server: added code to create SMVCBs with the dynamic model API (LIB61850-67)
- MMS server: added support for write access with component alternate access (LIB61850-414)
- MMS client: added function MmsConnection_writeVariableComponent to write to variables with alternate component access (LIB61850-414)
- make write access to RCB elements configurable according to ReportSettings (LIB61850-404)
- Added function IedConnection_setLocalAddress to define local IP address and optionally local port of a client connection (LIB61850-378)
- IED server: added ControlAction_getSynchroCheck and ControlAction_getInterlockCheck functions
Fixed bugs and vulnerabilities:
- fixed - IEC 61580 server: dataset is not released when RCB.Datset is set to empty string by client (LIB61850-425)
- PAL: fixed wrong order of function arguments for fread and fwrite functions
- MMS client: parsing of servicecsSupported in MMS init response is off by one (LIB61850-419)(#469)
- fixed - potential memory leaks in goose publisher code (#464)
- fixed - server sends dchg report when only dupd is enabled in RCB (LIB61850-411)
- GOOSE subscriber: fixed - possible heap corruption in parseAllData due to missing validity check in bit-string handling (LIB61850-402)
- IED server: fixed problem with implicit ResvTms setting when reserved with RptEna (LIB61850-400)
- IED server: fixed - segmentation fault when compiled with CONFIG_MMS_THREADLESS_STACK (LIB61850-398)
- fixed - MMS server: messages can be corrupted when TCP buffer is full (LIB61850-385)
- fixed - .NET: IedConenction.WriteDataSetValues throws a NullReferenceException (LIB61850-384)
- fixed - server send invalid response- when client uses wrong ctlModel (LIB61850-383) (#435)
- fixed - IedConnection_setRCBValuesAsync crashes when RCB is already reserved by other client (LIB61850-382)
- fixed - outstanding call not released in IedConnection_getDataSetDirectoryAsync (LIB61850-379)
Changes to version 1.5.2 (Dec 19, 2022)
---------------------------------------
New features and improvements:
- renamed TLSConfiguration_EventLevel to TLSEventLevel
- updated required mbedtls version to 2.28.x
- Added check for changed CRL on socket read/write. Added reset of renegotiation ssl cache on CRL add
- Fixing Security events messages to match IEC62351-100-3
- .NET API: Added support for TLS event handler (LIB61850-373)
- IED Server: added function to set time quality for internally updated times (LIB61850-372)
- added TLSConnection object to provide more context in TLS event callback (LIB61850-366)
- TLS: added TLS alert callbacks; support for session resumption with session IDs (LIB61850-339)
- MMS client: added function MmsConnection_sendRawData for test purposes
- changed StringUtils_createStringInBuffer function to consider max buffer size (LIB61850-333)
- replaced most str(n)cpy/str(n)cat calls (LIB61850-333)
- encode boolean true value as 0x01 instead of 0xff to avoid interoperability problems
- added IedServerConfig_setSyncIntegrityReportTimes/IedServerConfig_setSyncIntegrityReportTimes wrapper to .NET API (LIB61850-323)
- added feature: synchronization of integrity report times (LIB61850-323)
- server: added RCBEventHandler event types REPORT_CREATED and OVERFLOW
- added function ReportControlBlock_getResv
- mms_utility: added option to read data set directory
- .NET API: added IedServer.GetFunctionalConstrainedData method (LIB61850-317)
- RCBEventHandler: replaced GI event by purgeBuf event when client disables RCB instance (LIB61850-316)
- enabled TLS 1.2 support in mbedtls configuration
- improved MmsValue handling; fixed MmsValue(OCTET-STRIG) maximum size problem (LIB61850-150)
- IED server: improved control state machine performance (LIB61850-312)
Fixed bugs and vulnerabilities:
- fixed - dynamic model helper functions: Check added to Cancel object for CDC APC
- fixed wrong number in TLS event code define (LIB61850_366)
- fixed - servers sends object-access-unsupported on GetAllData when ReadAccessHandler is installed (LIB61850-370)
- fixed - endless loop sending reports when MMS PDU size is too small (LIB61850-365)
- fixed path traversal vulnerability in MMS file services (LIB61850-357)
- IED server: added missing call to getNextRoundedStartTime (LIB61850-323)
- fixed - server crashs when SyncIntegrityReportTimes is active and IntgPd=0 (LIB61850-355)
- fixed - missing API export declarations for functions IedServerConfig_setSyncIntegrityReportTimes and IedServerConfig_getSyncIntegrityReportTimes (LIB61850-353)
- IED server: fixed - possible deadlock when IedServer_lockDataModel is used from multiple threads (LIB61850-352)
- MMS server: fixed - possible deadlock in obtainFile-service/file upload task (LIB61850-351)
- MMS server: fixed potential null pointer dereference when confirmeServiceResponse for fileOpen is received with invoke-id 0 (LIB61850-348)
- MMS_SERVER: fixed bug in getNameList request handling when domain ID is too long (LIB61850-346)
- GOOSE subscriber: fixed vulnerabilities related to malformed bit-string, integer, and unsigned values (LIB61850-342)
- MMS server: fixed bug in handling of continueAfter parameter of getNameList request (LIB61850-341)
- fixed sscanf format string in config_file_parser.c
- fixed locking mechanism in logging.c (LIB61850-327)
- fixed problem: negative presentation layer and ACSE results are ignored by client
- fixed wrong buffer size in client side report handling
- fixed memory leak in server read request handling (LIB61850-325)
- fixed memory leak in reuse of client connection (related to socket extension buffer)
- fixed - TLS: CRL is ignored
- fixed wrong MMS protocol version check (#379)
- fixed - SV publisher encoding problem when svID or datset length > 127 bytes (LIB61850-315)(#382)
- IedServerConfig: added missing variable initialization
- fixed - server doesn't respond SBOw when waiting for select callback (LIB61850-313)
Changes to version 1.5.1 (Mar 11, 2022)
---------------------------------------
New features and improvements:
- added server side ReportControlBlock events and value access functions
- added functions Timestamp_fromMmsValue and Quality_toMmsValue
- made server report reservation compatible with Ed. 2.1 (LIB61850-293)
@ -54,63 +194,6 @@ Fixed bugs and vulnerabilities:
- IED server: For SBOes check test flag match when accepting operate (sSBOes8)
- IED server: Reject Cancel/SBOw in WaitForChange state - fixed problem with test case sCtl26
Changes to version 1.5.0
------------------------
- added support for time with ns resolution
- IEC 61850 server: control models - allow delaying select response with check handler (new handler return value CONTROL_WAITING_FOR_SELECT)
- IEC 61850 server: added support to listen on multiple IP addresses and ports (new function IedServer_addAccessPoint)
- added support for service tracking
- added tool support for transient data objects
- .NET API: added more functions to create and access server data model
- IED server - control model - send AddCause with operate- for DOes, SBOes control models
- IED server: integrated GOOSE publisher - lock data model during GOOSE retransmission to avoid corrupted GOOSE data
- added server example for dead band handling
- IED server: make presence of RCB.Owner configurable at runtime with function IedServerConfig_enableOwnerForRCB (B1502/S1634)
- IED server: make presence of BRCB.ResvTms configurable at runtime with function IedServerConfig_enableResvTmsForBRCB (F1558)
- restrict maximum recursion depth in BerDecoder_decodeLength when indefinite length encoding is used to avoid stack overflow when receiving malformed messages
- fixed oss-fuzz issues 31399, 31340, 31341, 31344, 31346
- IED server: fixed bug in log service - old-entry and old-entry-time not updated
- IED server: added new function IedServer_handleWriteAccessForComplexAttribute. Changed WriteAccessHandler behavior when ACCESS_POLICY_ALLOW.
- MMS server: add compile time configuration options to enable/disable fileDelete and fileRename services (fileRename is now disabled by default)
- MMS server: better data model lock handling for performance improvements
- Linux - Ethernet: replace IFF_PROMISC by IFF_ALLMULTI
- improvements in Python wrapper code
- IED server: control models - fixed bug that only one control is unselected when connection closes
- IED server: fixed bug - logs (journals) are added to all logical devices instead of just the parents
- IED Server: prevent integrated GOOSE publisher to crash when ethernet socket cannot be created
- IED server: make compatible with tissue 1178
- IED server: reporting - implemented behavior according to tissue 1432
- IED server: WriteAccessHandler can tell the stack not to update the value when returning DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE
- IED server: fixed problem that BL FC is not writable (#287)
- IEC 61850 client: fixed dead lock in IedConnection_getFileAsync when fileRead times out (#285)
- IED server: added ControlSelectStateChangedHandler callback for control mode
- Client: fixed - IedConnection_getRCBValues doesn't check type of server response (#283)
- GOOSE subscriber: changed maximum GoID size according to tissue 770 (129 bytes)
- IED server: send AddCause for invalid origin also in case of direct control models
- IED server: support for configuration of EditSG service and online visibility of SGCB.ResvTms at runtime
- IED server: changed types TrkOps and OptFlds to variable length bit strings
- MMS: changed handling of variable sized bit strings (now also accepts bit strings of larger size, ignoring the bits that exceed the specified size)
- IED server: add support for correct CBB handling (required for test case sAss4) and initiate error PDU
- IED server: add support for tissue 807 (owner attribute in RCB is only present when ReportSettings@owner attribute is true)
- IED server: implemented tissue 1453 also for writing to "RptId" (purgeBuf only executed when value changes)
- GOOSE subscriber: always copy GoID and DatSet from GOOSE message; always create new MmsValue instance for GOOSE data set when subscriber is observer
- IED server: added configuration file support for data set entries with array elements or array element components
- fixed problems in handling array elements and array element components
- fixed bug in MmsConnection_readMultipleVariables: send invaid messsage and memory access errors when too many items are passed to the function exhausting MMS payload size
- IEC 61850 server: fixed problem with test case sRp4 - RCB RptID attribute is not empty after writing empty string
- fixed program crash when normal mode parameers are missing in presentation layer (#252)
- IED Server/GOOSE: Don't send GOOSE message with new event while data model is locked
- GOOSE: added GOOSE observer feature (GooseSubscriber listening to all GOOSE messages) and GOOSE observer example
- COTP: fixed possible heap buffer overflow when handling message with invalid (zero) value in length field (#250)
- IEC 61850 server: fixed - cancel command for time activated control returns object-access-denied even in case of success
- IEC 61850 client: fixed bug - IedConnection_setRCBValuesAsync always return 0 instead of invoke-ID
- MMS: fixed problem in handling of indefinite length encoded BER elements
- IEC 61850 client: reporting - support data set entries with multiple reasons for inclusion
- Java tools: moved minTime, maxTime from GSEControl to GSE; updated GOOSE server example CID file
- IEC 61850 server: Added ControlAction_setError function - with this function the user application can control the error code used in LastApplError and CommandTermination messages
- IEC 61850 server: fixed problem with logging when log data set contains FCDO (#225)
Changes to version 1.4.2.1
--------------------------

@ -33,13 +33,16 @@ option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)
option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" ON)
option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF)
set(CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS 5 CACHE STRING "Configure the maximum number of get file tasks")
set(CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 100 CACHE STRING "Configure the maximum number of dataSet members")
option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON)
option(CONFIG_INCLUDE_GOOSE_SUPPORT "Build with GOOSE support" ON)
option(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB "Build with pre-compiled mbedtls dynamic library" OFF)
set(CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.16/library" CACHE STRING "Path to search for the mbedtls dynamic libraries" )
set(CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.16/include" CACHE STRING "Path to search for the mbedtls include files" )
set(CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/library" CACHE STRING "Path to search for the mbedtls dynamic libraries" )
set(CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include" CACHE STRING "Path to search for the mbedtls include files" )
# choose the library features which shall be included
option(CONFIG_IEC61850_CONTROL_SERVICE "Build with support for IEC 61850 control features" ON)
@ -49,10 +52,14 @@ option(CONFIG_IEC61850_SERVICE_TRACKING "Build with support for IEC 61850 servic
option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON)
option(CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL "Allow user provided callback to control read access" ON)
option(CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT "allow only configured clients (when pre-configured by ClientLN)" OFF)
option(CONFIG_IEC61850_L2_GOOSE "Build with support for L2 GOOSE (winpcap required on windows)" ON)
option(CONFIG_IEC61850_L2_SMV "Build with support for L2 SMV (winpcap required on windows)" ON)
option(CONFIG_IEC61850_R_GOOSE "Build with support for R-GOOSE (mbedtls required)" ON)
option(CONFIG_IEC61850_R_SMV "Build with support for R-SMV (mbedtls required)" ON)
option(CONFIG_IEC61850_SNTP_CLIENT "Build with SNTP client code" ON)
set(CONFIG_IEC61850_SG_RESVTMS 300 CACHE STRING "Configure the maximum number of SG RESVTMS")
set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "65536" CACHE STRING "Default buffer size for buffered reports in byte" )
# advanced options
@ -86,6 +93,74 @@ include_directories(
${CMAKE_CURRENT_LIST_DIR}/src/logging
)
if(MSVC AND MSVC_VERSION LESS 1800)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/src/vs
)
endif(MSVC AND MSVC_VERSION LESS 1800)
if(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
if(EXISTS "${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH}/mbedtls/build_info.h")
file (READ "${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH}/mbedtls/build_info.h" MBEDTLS_VERSION_FILE)
string (FIND "${MBEDTLS_VERSION_FILE}" "Mbed TLS 3.6." matchresult)
if(${matchresult} EQUAL -1)
set(WITH_MBEDTLS 1)
else()
set(WITH_MBEDTLS3 1)
message("Using external mbedtls 3.6.x")
endif ()
else()
set(WITH_MBEDTLS 1)
endif(EXISTS "${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH}/mbedtls/build_info.h")
set(USE_PREBUILD_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR ${CONFIG_EXTERNAL_MBEDTLS_INCLUDE_PATH})
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h)
set(FOUND_SQLITE3_SOURCE 1)
set(SQLITE_INCLUDE_DIR"${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite")
message("Found sqlite3 source in third_party folder -> can compile with log service support")
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/sqlite/sqlite3.h)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0)
set(WITH_MBEDTLS3 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0/include")
else()
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
set(WITH_MBEDTLS 1)
set(MBEDTLS_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28/include")
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.28)
endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-3.6.0)
if(WITH_MBEDTLS OR WITH_MBEDTLS3)
add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1)
if (CONFIG_IEC61850_R_GOOSE)
set(BUILD_R_GOOSE_EXAMPLES 1)
endif (CONFIG_IEC61850_R_GOOSE)
if (CONFIG_IEC61850_R_SMV)
set(BUILD_R_SMV_EXAMPLES 1)
endif (CONFIG_IEC61850_R_SMV)
if (CONFIG_IEC61850_SNTP_CLIENT)
set(BUILD_SNTP_CLIENT_EXAMPLES 1)
endif (CONFIG_IEC61850_SNTP_CLIENT)
else(WITH_MBEDTLS OR WITH_MBEDTLS3)
set(CONFIG_IEC61850_R_GOOSE 0)
set(CONFIG_IEC61850_R_SMV 0)
endif(WITH_MBEDTLS OR WITH_MBEDTLS3)
set(API_HEADERS
hal/inc/hal_base.h
hal/inc/hal_time.h
@ -94,6 +169,7 @@ set(API_HEADERS
hal/inc/hal_ethernet.h
hal/inc/hal_socket.h
hal/inc/tls_config.h
hal/inc/tls_ciphers.h
src/common/inc/libiec61850_common_api.h
src/common/inc/linked_list.h
src/common/inc/sntp_client.h
@ -162,6 +238,11 @@ if (SUPPORT_REDUNDANT_DECLS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wredundant-decls")
endif(SUPPORT_REDUNDANT_DECLS)
check_c_compiler_flag("-Wundef" SUPPORT_UNDEF)
if (SUPPORT_UNDEF)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wundef")
endif(SUPPORT_UNDEF)
# write the detected stuff to this file
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/stack_config.h.cmake

@ -72,18 +72,21 @@ LIB_INCLUDE_DIRS += src/sampled_values
LIB_INCLUDE_DIRS += src/iec61850/inc
LIB_INCLUDE_DIRS += src/iec61850/inc_private
LIB_INCLUDE_DIRS += src/logging
LIB_INCLUDE_DIRS += src/r_session
LIB_INCLUDE_DIRS += src/tls
ifeq ($(HAL_IMPL), WIN32)
LIB_INCLUDE_DIRS += third_party/winpcap/Include
endif
ifdef WITH_MBEDTLS
LIB_SOURCE_DIRS += third_party/mbedtls/mbedtls-2.16/library
LIB_SOURCE_DIRS += third_party/mbedtls/mbedtls-2.28/library
LIB_SOURCE_DIRS += hal/tls/mbedtls
LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.16/include
LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.28/include
LIB_INCLUDE_DIRS += hal/tls/mbedtls
CFLAGS += -D'MBEDTLS_CONFIG_FILE="mbedtls_config.h"'
CFLAGS += -D'CONFIG_MMS_SUPPORT_TLS=1'
CFLAGS += -D'CONFIG_IEC61850_R_GOOSE=1'
CFLAGS += -D'CONFIG_IEC61850_R_SMV=1'
endif
LIB_INCLUDES = $(addprefix -I,$(LIB_INCLUDE_DIRS))
@ -92,14 +95,17 @@ ifndef INSTALL_PREFIX
INSTALL_PREFIX = ./.install
endif
LIB_API_HEADER_FILES = hal/inc/hal_time.h
LIB_API_HEADER_FILES += hal/inc/hal_base.h
LIB_API_HEADER_FILES += hal/inc/hal_time.h
LIB_API_HEADER_FILES += hal/inc/hal_thread.h
LIB_API_HEADER_FILES += hal/inc/hal_filesystem.h
LIB_API_HEADER_FILES += hal/inc/hal_ethernet.h
LIB_API_HEADER_FILES += hal/inc/hal_socket.h
LIB_API_HEADER_FILES += hal/inc/tls_config.h
LIB_API_HEADER_FILES += hal/inc/lib_memory.h
LIB_API_HEADER_FILES += hal/inc/hal_base.h
LIB_API_HEADER_FILES += hal/inc/tls_ciphers.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/sntp_client.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
@ -119,6 +125,7 @@ LIB_API_HEADER_FILES += src/goose/goose_receiver.h
LIB_API_HEADER_FILES += src/goose/goose_publisher.h
LIB_API_HEADER_FILES += src/sampled_values/sv_subscriber.h
LIB_API_HEADER_FILES += src/sampled_values/sv_publisher.h
LIB_API_HEADER_FILES += src/r_session/r_session.h
LIB_API_HEADER_FILES += src/logging/logging_api.h
get_sources_from_directory = $(wildcard $1/*.c)
@ -137,13 +144,13 @@ ifneq ($(HAL_IMPL), WIN32)
CFLAGS += -Wuninitialized
endif
CFLAGS += -Wsign-compare
CFLAGS += -Wpointer-arith
CFLAGS += -Wnested-externs
CFLAGS += -Wmissing-declarations
CFLAGS += -Wshadow
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-sign-compare
CFLAGS += -Wno-format
#CFLAGS += -Wconditional-uninitialized
#CFLAGS += -Werror

@ -1,7 +1,5 @@
# README libIEC61850
[![Build Status](https://travis-ci.org/mz-automation/libiec61850.svg?branch=master)](https://travis-ci.org/mz-automation/libiec61850)
This file is part of the documentation of **libIEC61850**. More documentation can be found online at http://libiec61850.com.
The API documentation can be found here:
@ -53,9 +51,9 @@ The library support the following IEC 61850 protocol features:
* Setting group handling
* Support for service tracking
* GOOSE and SV control block handling
* Support for R-session protocol/R-GOOSE/R-SMV
* Simple SNTP client code
* TLS support
* Support for R-session protocol/R-GOOSE/R-SMV (BETA)
* Simple SNTP client code (BETA)
* TLS support (IEC 62351-3/4)
* C and C#/.NET API
@ -88,9 +86,19 @@ You can test the server examples by using a generic client or the provided clien
## Building the library with TLS support
Download, unpack, and copy mbedtls-2.16 into the third_party/mbedtls folder.
The library has an implementation agnostic interface for TLS configuration.
Currently it comes with two different implementations of this interface.
One for the old mbedtls 2.28 LTS version that support TLS versions up to TLS 1.2.
Another implementation support the current mbedtls 3.6.0 version. This newer mbedtls version supports only TLS 1.2 and 1.3.
NOTE: The current version support mbedtls version 2.16. When you download the source archive from https://tls.mbed.org/ you have to rename the extracted folder to "mbedtls-2.16".
### mbedtls 2.28
Download, unpack, and copy mbedtls-2.28 into the third_party/mbedtls folder.
NOTE: The current version support mbedtls version 2.28. When you download the source archive from https://tls.mbed.org/ you have to rename the extracted folder to "mbedtls-2.28".
In the main libiec61850 folder run
@ -98,7 +106,21 @@ In the main libiec61850 folder run
make WITH_MBEDTLS=1
```
When using CMake the library is built automatically with TLS support when the folder third_party/mbedtls/mbedtls-2.16 is present.
When using CMake the library is built automatically with TLS support when the folder third_party/mbedtls/mbedtls-2.28 is present.
### mbedtls 3.6
Alternatively you can also use mbedtls 3.6.
Download, unpack, and copy mbedtls-3.6.0 into the third_party/mbedtls folder
In the main libiec61850 folder run
```
make WITH_MBEDTLS3=1
```
When using CMake the library is built automatically with TLS support when the folder third_party/mbedtls/mbedtls-3.6.0 is present.
## Installing the library and the API headers
@ -119,7 +141,7 @@ For the cmake build script you have to provide the CMAKE_INSTALL_PREFIX variable
## Building on windows with GOOSE support
To build the library and run libiec61850 applications with GOOSE support on Windows (7/8/10) the use of a third-party library (winpcap) is required. This is necessary because current versions of Windows have no working support for raw sockets. You can download winpcap here (http://www.winpcap.org).
To build the library and run libiec61850 applications with GOOSE support on Windows (10/11) the use of a third-party library (winpcap) is required. This is necessary because current versions of Windows have no working support for raw sockets. You can download winpcap here (http://www.winpcap.org).
1. Download and install winpcap. Make sure that the winpcap driver is loaded at boot time (you can choose this option at the last screen of the winpcap installer).
2. Reboot the system (you can do this also later, but you need to reboot or load the winpcap driver before running any llibiec61850 applications that use GOOSE).

@ -68,36 +68,20 @@
/* maximum COTP (ISO 8073) TPDU size - valid range is 1024 - 8192 */
#define CONFIG_COTP_MAX_TPDU_SIZE 8192
/* Ethernet interface ID for GOOSE and SV */
/* Ethernet interface ID for L2 GOOSE and SV */
#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. */
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
/* Set to 1 to include generic GOOSE support in the build. Otherwise set to 0 */
#define CONFIG_INCLUDE_GOOSE_SUPPORT 1
/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */
/* Set to 1 to include generic Sampled Values support in the build. Otherwise set to 0 */
#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
/* Set to 1 to compile for edition 1 server - default is 0 to compile for edition 2 */
#define CONFIG_IEC61850_EDITION_1 0
#ifdef _WIN32
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
#ifdef EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT
#undef CONFIG_INCLUDE_GOOSE_SUPPORT
#endif
#define CONFIG_INCLUDE_GOOSE_SUPPORT 0
#define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1
#undef CONFIG_ETHERNET_INTERFACE_ID
#define CONFIG_ETHERNET_INTERFACE_ID "0"
#endif
#endif
/* The GOOSE retransmission interval in ms for the stable condition - i.e. no monitored value changed */
#define CONFIG_GOOSE_STABLE_STATE_TRANSMISSION_INTERVAL 5000
@ -170,7 +154,7 @@
/* allow application to set server identity (for MMS identity service) at runtime */
#define CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY 1
/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
/* Force memory alignment - required for some platforms (requires more memory for buffered reporting) */
#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1
/* compile with support for R-GOOSE (mbedtls requried) */
@ -179,9 +163,36 @@
/* compile with support for R-SMV (mbedtls required) */
#define CONFIG_IEC61850_R_SMV 0
/* compile with support for L2 GOOSE */
#define CONFIG_IEC61850_L2_GOOSE 1
/* compile with support for L2 SMV */
#define CONFIG_IEC61850_L2_SMV 1
/* compile SNTP client code */
#define CONFIG_IEC61850_SNTP_CLIENT 0
#ifdef _WIN32
/* L2 GOOSE/SMV will be disabled for Windows if ethernet support (winpcap) is not available */
#ifdef EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_IEC61850_L2_GOOSE
#undef CONFIG_IEC61850_L2_GOOSE
#endif
#ifdef CONFIG_IEC61850_L2_SMV
#undef CONFIG_IEC61850_L2_SMV
#endif
#define CONFIG_IEC61850_L2_GOOSE 0
#define CONFIG_IEC61850_L2_SMV 0
#define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1
#undef CONFIG_ETHERNET_INTERFACE_ID
#define CONFIG_ETHERNET_INTERFACE_ID "0"
#endif
#endif
/* overwrite default results for MMS identify service */
/* #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" */
/* #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" */
@ -238,9 +249,6 @@
#define CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS 0
/* use short FC defines as in old API */
#define CONFIG_PROVIDE_OLD_FC_DEFINES 0
/* Support user access to raw messages */
#define CONFIG_MMS_RAW_MESSAGE_LOGGING 1
@ -252,10 +260,24 @@
/* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1
/* Define the default number of the maximum outstanding calls allowed by the caller (client) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
/************************************************************************************
* Check configuration for consistency - DO NOT MODIFY THIS PART!
************************************************************************************/
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!"
#endif
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!"
#endif
#if (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -68,10 +68,10 @@
/* #define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0" */
/* #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 */
/* Set to 1 to include generic GOOSE support in the build. Otherwise set to 0 */
#cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT
/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */
/* Set to 1 to include generic Sampled Values support in the build. Otherwise set to 0 */
#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
/* compile with support for R-GOOSE (mbedtls requried) */
@ -80,6 +80,12 @@
/* compile with support for R-SMV (mbedtls required) */
#cmakedefine01 CONFIG_IEC61850_R_SMV
/* compile with support for L2 GOOSE */
#cmakedefine01 CONFIG_IEC61850_L2_GOOSE
/* compile with support for L2 SMV */
#cmakedefine01 CONFIG_IEC61850_L2_SMV
/* compile SNTP client code */
#cmakedefine01 CONFIG_IEC61850_SNTP_CLIENT
@ -88,12 +94,16 @@
#ifdef _WIN32
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
/* L2 GOOSE/SMV will be disabled for Windows if ethernet support (winpcap) is not available */
#ifdef EXCLUDE_ETHERNET_WINDOWS
#ifdef CONFIG_INCLUDE_GOOSE_SUPPORT
#undef CONFIG_INCLUDE_GOOSE_SUPPORT
#ifdef CONFIG_IEC61850_L2_GOOSE
#undef CONFIG_IEC61850_L2_GOOSE
#endif
#ifdef CONFIG_IEC61850_L2_SMV
#undef CONFIG_IEC61850_L2_SMV
#endif
#define CONFIG_INCLUDE_GOOSE_SUPPORT 0
#define CONFIG_IEC61850_L2_GOOSE 0
#define CONFIG_IEC61850_L2_SMV 0
#define CONFIG_INCUDE_ETHERNET_WINDOWS 0
#else
#define CONFIG_INCLUDE_ETHERNET_WINDOWS 1
@ -155,7 +165,7 @@
#cmakedefine01 CONFIG_IEC61850_SETTING_GROUPS
/* default reservation time of a setting group control block in s */
#define CONFIG_IEC61850_SG_RESVTMS 100
#cmakedefine CONFIG_IEC61850_SG_RESVTMS @CONFIG_IEC61850_SG_RESVTMS@
/* include support for IEC 61850 log services */
#cmakedefine01 CONFIG_IEC61850_LOG_SERVICE
@ -169,7 +179,7 @@
/* allow application to set server identity (for MMS identity service) at runtime */
#define CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY 1
/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
/* Force memory alignment - required for some platforms (requires more memory for buffered reporting) */
#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1
/* default results for MMS identify service */
@ -196,7 +206,10 @@
#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10
/* Maximum number of the members in a data set (named variable list) */
#define CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 50
#cmakedefine CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS @CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS@
/* Maximum number of get file tasks */
#cmakedefine CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS @CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS@
/* Definition of supported services */
#define MMS_DEFAULT_PROFILE 1
@ -224,9 +237,6 @@
#define CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS 0
/* use short FC defines as in old API */
#define CONFIG_PROVIDE_OLD_FC_DEFINES 0
/* Support user acccess to raw messages */
#cmakedefine01 CONFIG_MMS_RAW_MESSAGE_LOGGING
@ -238,10 +248,24 @@
/* enable to configure MmsServer at runtime */
#define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1
/* Define the default number of the maximum outstanding calls allowed by the caller (client) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5
/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */
#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5
/************************************************************************************
* Check configuration for consistency - DO NOT MODIFY THIS PART!
************************************************************************************/
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!"
#endif
#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1)
#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!"
#endif
#if (MMS_JOURNAL_SERVICE != 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)

@ -5,13 +5,13 @@
*/
#include "iec61850_client.h"
#include "hal_thread.h"
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv) {
char* hostname;
int main(int argc, char **argv)
{
char *hostname;
int tcpPort = 102;
if (argc > 1)
@ -28,72 +28,83 @@ int main(int argc, char** argv) {
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
if (error == IED_ERROR_OK)
{
/************************
* Direct control
***********************/
bool led4State = false;
ControlObjectClient controlLED1
= ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO1", con);
ControlObjectClient controlLED1 = ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO1", con);
ControlObjectClient controlLED2
= ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO2", con);
ControlObjectClient controlLED2 = ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO2", con);
ControlObjectClient controlLED3
= ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO3", con);
ControlObjectClient controlLED3 = ControlObjectClient_create("beagleGenericIO/GGIO1.SPCSO3", con);
ControlObjectClient controlLED4
= ControlObjectClient_create("beagleGenericIO/GGIO1.DPCSO1", con);
ControlObjectClient controlLED4 = ControlObjectClient_create("beagleGenericIO/GGIO1.DPCSO1", con);
MmsValue* ctlValOn = MmsValue_newBoolean(true);
MmsValue *ctlValOn = MmsValue_newBoolean(true);
MmsValue* ctlValOff = MmsValue_newBoolean(false);
MmsValue *ctlValOff = MmsValue_newBoolean(false);
if (!ControlObjectClient_operate(controlLED1, ctlValOff, 0)) goto control_error;
if (!ControlObjectClient_operate(controlLED1, ctlValOff, 0))
goto control_error;
ControlObjectClient_select(controlLED2);
if (!ControlObjectClient_operate(controlLED2, ctlValOff, 0)) goto control_error;
if (!ControlObjectClient_operate(controlLED2, ctlValOff, 0))
goto control_error;
if (!ControlObjectClient_operate(controlLED4, ctlValOff, 0))
goto control_error;
if (!ControlObjectClient_operate(controlLED4, ctlValOff, 0)) goto control_error;
while (1)
{
if (!ControlObjectClient_operate(controlLED3, ctlValOff, 0))
goto control_error;
if (!ControlObjectClient_operate(controlLED1, ctlValOn, 0))
goto control_error;
while (1) {
if (!ControlObjectClient_operate(controlLED3, ctlValOff, 0)) goto control_error;
if (!ControlObjectClient_operate(controlLED1, ctlValOn, 0)) goto control_error;
Thread_sleep(1000);
if (!ControlObjectClient_operate(controlLED1, ctlValOff, 0)) goto control_error;
if (!ControlObjectClient_operate(controlLED1, ctlValOff, 0))
goto control_error;
ControlObjectClient_select(controlLED2);
if (!ControlObjectClient_operate(controlLED2, ctlValOn, 0)) goto control_error;
if (!ControlObjectClient_operate(controlLED2, ctlValOn, 0))
goto control_error;
Thread_sleep(1000);
ControlObjectClient_select(controlLED2);
if (!ControlObjectClient_operate(controlLED2, ctlValOff, 0)) goto control_error;
if (!ControlObjectClient_operate(controlLED2, ctlValOff, 0))
goto control_error;
if (!ControlObjectClient_operate(controlLED3, ctlValOn, 0))
goto control_error;
if (!ControlObjectClient_operate(controlLED3, ctlValOn, 0)) goto control_error;
Thread_sleep(1000);
if (led4State == false) {
if (!ControlObjectClient_operate(controlLED4, ctlValOn, 0)) goto control_error;
if (led4State == false)
{
if (!ControlObjectClient_operate(controlLED4, ctlValOn, 0))
goto control_error;
led4State = true;
}
else {
if (!ControlObjectClient_operate(controlLED4, ctlValOff, 0)) goto control_error;
else
{
if (!ControlObjectClient_operate(controlLED4, ctlValOff, 0))
goto control_error;
led4State = false;
}
}
goto exit_control_loop;
control_error:
control_error:
printf("Error controlling device!\n");
exit_control_loop:
exit_control_loop:
MmsValue_delete(ctlValOn);
MmsValue_delete(ctlValOff);
@ -105,11 +116,10 @@ exit_control_loop:
IedConnection_close(con);
}
else {
printf("Connection failed!\n");
else
{
printf("Connection failed!\n");
}
IedConnection_destroy(con);
}

@ -2,7 +2,6 @@
* beagle_demo.c
*
* This demo shows how to connect the libiec61850 server stack to a real device.
*
*/
#include "iec61850_server.h"
@ -31,21 +30,24 @@ static uint32_t dpcState = 0;
void sigint_handler(int signalId)
{
running = 0;
running = 0;
}
static void
connectionIndicationHandler(IedServer server, ClientConnection connection, bool connected, void* parameter)
connectionIndicationHandler(IedServer server, ClientConnection connection, bool connected, void *parameter)
{
const char* clientAddress = ClientConnection_getPeerAddress(connection);
const char *clientAddress = ClientConnection_getPeerAddress(connection);
if (connected) {
if (connected)
{
printf("BeagleDemoServer: new client connection from %s\n", clientAddress);
}
else {
else
{
printf("BeagleDemoServer: client connection from %s closed\n", clientAddress);
if (controllingClient == connection) {
if (controllingClient == connection)
{
printf("Controlling client has closed connection -> switch to automatic operation mode\n");
controllingClient = NULL;
automaticOperationMode = true;
@ -54,9 +56,10 @@ connectionIndicationHandler(IedServer server, ClientConnection connection, bool
}
static CheckHandlerResult
performCheckHandler(ControlAction action, void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, ClientConnection connection)
performCheckHandler(ControlAction action, void *parameter, MmsValue *ctlVal, bool test, bool interlockCheck, ClientConnection connection)
{
if (controllingClient == NULL) {
if (controllingClient == NULL)
{
printf("Client takes control -> switch to remote control operation mode\n");
controllingClient = connection;
automaticOperationMode = false;
@ -74,7 +77,8 @@ performCheckHandler(ControlAction action, void* parameter, MmsValue* ctlVal, boo
}
static void
updateLED1stVal(bool newLedState, uint64_t timeStamp) {
updateLED1stVal(bool newLedState, uint64_t timeStamp)
{
switchLED(LED1, newLedState);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp);
@ -83,7 +87,8 @@ updateLED1stVal(bool newLedState, uint64_t timeStamp) {
}
static void
updateLED2stVal(bool newLedState, uint64_t timeStamp) {
updateLED2stVal(bool newLedState, uint64_t timeStamp)
{
switchLED(LED2, newLedState);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp);
@ -92,7 +97,8 @@ updateLED2stVal(bool newLedState, uint64_t timeStamp) {
}
static void
updateLED3stVal(bool newLedState, uint64_t timeStamp) {
updateLED3stVal(bool newLedState, uint64_t timeStamp)
{
switchLED(LED3, newLedState);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp);
@ -101,7 +107,7 @@ updateLED3stVal(bool newLedState, uint64_t timeStamp) {
}
static ControlHandlerResult
controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* value, bool test)
controlHandlerForBinaryOutput(ControlAction action, void *parameter, MmsValue *value, bool test)
{
if (test)
return CONTROL_RESULT_OK;
@ -117,30 +123,32 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v
updateLED2stVal(newState, timeStamp);
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3)
updateLED3stVal(newState, timeStamp);
updateLED3stVal(newState, timeStamp);
if (parameter == IEDMODEL_GenericIO_GGIO1_DPCSO1) { /* example for Double Point Control - DPC */
if (parameter == IEDMODEL_GenericIO_GGIO1_DPCSO1) /* example for Double Point Control - DPC */
{
Dbpos dpcState = DBPOS_INTERMEDIATE_STATE;
dpcState = 0; /* DPC_STATE_INTERMEDIATE */
IedServer_updateBitStringAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal, dpcState);
IedServer_updateDbposValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal, dpcState);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_t, timeStamp);
if (newState) {
if (newState)
{
flashLED(LED4);
Thread_sleep(3000);
switchLED(LED4, 1);
dpcState = 2; /* DPC_STATE_ON */
dpcState = DBPOS_ON;
}
else {
else
{
flashLED(LED4);
Thread_sleep(3000);
switchLED(LED4, 0);
dpcState = 1; /* DPC_STATE_OFF */
dpcState = DBPOS_OFF;
}
IedServer_updateBitStringAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal, dpcState);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_t, timeStamp);
IedServer_updateDbposValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal, dpcState);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_t, Hal_getTimeInMs());
}
return CONTROL_RESULT_OK;
@ -151,29 +159,28 @@ static int ledOffTimeMs = 1000;
static int32_t opCnt = 0;
static ControlHandlerResult
controlHandlerForInt32Controls(ControlAction action, void* parameter, MmsValue* value, bool test)
controlHandlerForInt32Controls(ControlAction action, void *parameter, MmsValue *value, bool test)
{
if (test)
return CONTROL_RESULT_OK;
if (test)
return CONTROL_RESULT_OK;
if (parameter == IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs) {
int32_t newValue = MmsValue_toInt32(value);
if (parameter == IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs)
{
int32_t newValue = MmsValue_toInt32(value);
opCnt = newValue;
opCnt = newValue;
uint64_t currentTime = Hal_getTimeInMs();
uint64_t currentTime = Hal_getTimeInMs();
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t, currentTime);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal, opCnt);
}
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t, currentTime);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal, opCnt);
}
return CONTROL_RESULT_OK;
return CONTROL_RESULT_OK;
}
static MmsDataAccessError
int32WriteAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnection connection, void* parameter)
int32WriteAccessHandler(DataAttribute *dataAttribute, MmsValue *value, ClientConnection connection, void *parameter)
{
int newValue = MmsValue_toInt32(value);
@ -181,8 +188,8 @@ int32WriteAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientCo
if (newValue < 0)
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
if (dataAttribute == IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal) {
if (dataAttribute == IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal)
{
printf("New value for TIM_GAPC1.OpDlTmms.setVal = %i\n", newValue);
ledOffTimeMs = newValue;
@ -190,8 +197,8 @@ int32WriteAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientCo
return DATA_ACCESS_ERROR_SUCCESS;
}
if (dataAttribute == IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal) {
if (dataAttribute == IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal)
{
printf("New value for TIM_GAPC1.RsDlTmms.setVal = %i\n", newValue);
ledOnTimeMs = newValue;
@ -202,130 +209,130 @@ int32WriteAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientCo
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
int main(int argc, char** argv) {
int main(int argc, char **argv)
{
initLEDs();
iedServer = IedServer_create(&iedModel);
iedServer = IedServer_create(&iedModel);
/* Set control callback handlers */
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionIndicationHandler, NULL);
/* Set control callback handlers */
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler)connectionIndicationHandler, NULL);
IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlPerformCheckHandler)performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler)controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2,
(ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO2);
(ControlPerformCheckHandler)performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO2);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO2);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler)controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO2);
IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3,
(ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO3);
(ControlPerformCheckHandler)performCheckHandler, IEDMODEL_GenericIO_GGIO1_SPCSO3);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO3);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler)controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO3);
IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1,
(ControlPerformCheckHandler) performCheckHandler, IEDMODEL_GenericIO_GGIO1_DPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1, (ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_DPCSO1);
(ControlPerformCheckHandler)performCheckHandler, IEDMODEL_GenericIO_GGIO1_DPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1, (ControlHandler)controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_DPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs, (ControlHandler) controlHandlerForInt32Controls,
IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs, (ControlHandler)controlHandlerForInt32Controls,
IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs);
/* Initialize process values */
MmsValue* DPCSO1_stVal = IedServer_getAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal);
MmsValue_setBitStringFromInteger(DPCSO1_stVal, 1); /* set DPC to OFF */
/* Initialize process values */
MmsValue *DPCSO1_stVal = IedServer_getAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_DPCSO1_stVal);
MmsValue_setBitStringFromInteger(DPCSO1_stVal, 1); /* set DPC to OFF */
/* Intitalize setting values */
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal, ledOffTimeMs);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal, ledOnTimeMs);
/* Set callback handler for settings */
IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal, int32WriteAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal, int32WriteAccessHandler, NULL);
/* Intitalize setting values */
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal, ledOffTimeMs);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal, ledOnTimeMs);
/* Set callback handler for settings */
IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpDlTmms_setVal, int32WriteAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_RsDlTmms_setVal, int32WriteAccessHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");
IedServer_destroy(iedServer);
exit(-1);
}
running = 1;
signal(SIGINT, sigint_handler);
if (!IedServer_isRunning(iedServer))
{
printf("Starting server failed! Exit.\n");
IedServer_destroy(iedServer);
exit(-1);
}
float t = 0.f;
running = 1;
bool ledStateValue = false;
signal(SIGINT, sigint_handler);
uint64_t nextLedToggleTime = Hal_getTimeInMs() + 1000;
float t = 0.f;
while (running) {
uint64_t currentTime = Hal_getTimeInMs();
bool ledStateValue = false;
if (automaticOperationMode) {
if (nextLedToggleTime <= currentTime) {
uint64_t nextLedToggleTime = Hal_getTimeInMs() + 1000;
while (running)
{
uint64_t currentTime = Hal_getTimeInMs();
if (ledStateValue)
nextLedToggleTime = currentTime + ledOffTimeMs;
else
nextLedToggleTime = currentTime + ledOnTimeMs;
if (automaticOperationMode)
{
if (nextLedToggleTime <= currentTime)
{
if (ledStateValue)
nextLedToggleTime = currentTime + ledOffTimeMs;
else
nextLedToggleTime = currentTime + ledOnTimeMs;
ledStateValue = !ledStateValue;
ledStateValue = !ledStateValue;
if (ledStateValue) {
opCnt++;
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t, currentTime);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal, opCnt);
}
if (ledStateValue)
{
opCnt++;
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_t, currentTime);
IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_GenericIO_TIM_GAPC1_OpCntRs_stVal, opCnt);
}
updateLED1stVal(ledStateValue, currentTime);
updateLED2stVal(ledStateValue, currentTime);
updateLED3stVal(ledStateValue, currentTime);
}
}
updateLED1stVal(ledStateValue, currentTime);
updateLED2stVal(ledStateValue, currentTime);
updateLED3stVal(ledStateValue, currentTime);
}
}
t += 0.1f;
t += 0.1f;
IedServer_lockDataModel(iedServer);
IedServer_lockDataModel(iedServer);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, sinf(t));
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, currentTime);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, sinf(t));
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, currentTime);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, sinf(t + 1.f));
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, currentTime);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, sinf(t + 1.f));
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, currentTime);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, sinf(t + 2.f));
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, currentTime);
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, currentTime);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, sinf(t + 3.f));
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, currentTime);
IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_q, QUALITY_VALIDITY_GOOD);
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, currentTime);
IedServer_unlockDataModel(iedServer);
IedServer_unlockDataModel(iedServer);
Thread_sleep(100);
}
Thread_sleep(100);
}
/* stop MMS server - close TCP server socket and all client sockets */
IedServer_stop(iedServer);
/* stop MMS server - close TCP server socket and all client sockets */
IedServer_stop(iedServer);
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
} /* main() */

@ -6,9 +6,8 @@
#define BEAGLEBONE_LEDS_H_
/* set to 1 if you want to run the demo on a PC */
//#define SIMULATED
/* define SIMULATED if you want to run the demo on a PC */
#define SIMULATED
/* select correct file paths to access LEDs - depends on beaglebones linux distro/version */

File diff suppressed because it is too large Load Diff

@ -775,7 +775,10 @@ namespace IEC61850
Dispose (true);
}
~ControlObject()
{
Dispose (false);
}
}
}

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Library</OutputType>
<RootNamespace>iec61850dotnet</RootNamespace>
<AssemblyName>iec61850dotnet</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

@ -1,7 +1,7 @@
/*
* IEC61850ClientAPI.cs
*
* Copyright 2014-2021 Michael Zillgith
* Copyright 2014-2023 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -431,12 +431,18 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 IedConnection_getRequestTimeout(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_setMaxOutstandingCalls(IntPtr self, int calling, int called);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_setTimeQuality(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool leapSecondKnown, [MarshalAs(UnmanagedType.I1)] bool clockFailure, [MarshalAs(UnmanagedType.I1)] bool clockNotSynchronized, int subsecondPrecision);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_connect(IntPtr self, out int error, string hostname, int tcpPort);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_setLocalAddress(IntPtr self, string localIpAddress, int localPort);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_abort(IntPtr self, out int error);
@ -556,6 +562,12 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_installStateChangedHandler(IntPtr connection, InternalStateChangedHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_ignoreReadAccess(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool ignore);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_ignoreClientRequests(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool ignore);
/*********************
* Async functions
*********************/
@ -812,6 +824,16 @@ namespace IEC61850
}
}
/// <summary>
/// Set the maximum number outstanding calls allowed for this connection
/// </summary>
/// <param name="calling">the maximum outstanding calls allowed by the caller (client)</param>
/// <param name="called">the maximum outstanding calls allowed by the called endpoint (server)</param>
public void SetMaxOutstandingCalls(int calling, int called)
{
IedConnection_setMaxOutstandingCalls(connection, calling, called);
}
/// <summary>
/// Gets or sets the maximum size if a PDU (has to be set before calling connect!).
/// </summary>
@ -894,6 +916,25 @@ namespace IEC61850
Connect(hostname, -1);
}
/// <summary>
/// Set the local IP address and port to be used by the client
/// </summary>
/// <param name="localIpAddress">the local IP address or hostname</param>
/// <param name="localPort">the local TCP port to use. When 0 the OS will chose the TCP port to use.</param>
public void SetLocalAddress(string localIpAddress, int localPort)
{
IedConnection_setLocalAddress(connection, localIpAddress, localPort);
}
/// <summary>
/// Set the local IP address to be used by the client
/// </summary>
/// <param name="localIpAddress">the local IP address or hostname</param>
public void SetLocalAddress(string localIpAddress)
{
IedConnection_setLocalAddress(connection, localIpAddress, 0);
}
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public ControlObject CreateControlObject(string objectReference)
{
@ -1153,6 +1194,9 @@ namespace IEC61850
private static List<MmsJournalEntry> WrapNativeLogQueryResult(IntPtr linkedList)
{
if (linkedList == IntPtr.Zero)
return null;
List<MmsJournalEntry> journalEntries = new List<MmsJournalEntry>();
IntPtr element = LinkedList_getNext(linkedList);
@ -1923,6 +1967,24 @@ namespace IEC61850
}
}
/// <summary>
/// Ignore all MMS requests from clients (for testing purposes)
/// </summary>
/// <param name="ignore">when true all requests from clients will be ignored</param>
public void IgnoreClientRequests(bool ignore)
{
IedServer_ignoreClientRequests(connection, ignore);
}
/// <summary>
/// Temporarily ignore read requests (for testing purposes)
/// </summary>
/// <param name="ignore">true to ignore read requests, false to handle read requests.</param>
public void IgnoreReadAccess(bool ignore)
{
IedServer_ignoreReadAccess(connection, ignore);
}
/// <summary>
/// Read the values of a data set (GetDataSetValues service).
/// </summary>
@ -1993,7 +2055,6 @@ namespace IEC61850
if (accessResults != IntPtr.Zero)
{
IntPtr element = LinkedList_getNext(accessResults);
while (element != IntPtr.Zero)
@ -2004,6 +2065,9 @@ namespace IEC61850
MmsDataAccessError dataAccessError = accessResultValue.GetDataAccessError();
if (accessResultList == null)
accessResultList = new List<MmsDataAccessError>();
accessResultList.Add(dataAccessError);
element = LinkedList_getNext(element);
@ -2214,22 +2278,27 @@ namespace IEC61850
GetDataSetDirectoryHandler handler = callbackInfo.Item1;
object handlerParameter = callbackInfo.Item2;
IntPtr element = LinkedList_getNext(dataSetDirectory);
handle.Free();
List<string> newList = new List<string>();
List<string> newList = null;
while (element != IntPtr.Zero)
if (dataSetDirectory != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList = new List<string>();
newList.Add(dataObject);
IntPtr element = LinkedList_getNext(dataSetDirectory);
element = LinkedList_getNext(element);
}
while (element != IntPtr.Zero)
{
string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element));
newList.Add(dataObject);
LinkedList_destroy(dataSetDirectory);
element = LinkedList_getNext(element);
}
LinkedList_destroy(dataSetDirectory);
}
handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable);
}
@ -2404,11 +2473,9 @@ namespace IEC61850
dataSet = new DataSet(nativeDataSet);
}
handler(invokeId, handlerParameter, clientError, dataSet);
}
public delegate void ReadDataSetHandler(UInt32 invokeId,object parameter,IedClientError err,DataSet dataSet);
/// <summary>
@ -2542,7 +2609,6 @@ namespace IEC61850
{
handler(invokeId, handlerParameter, clientError, null, moreFollows);
}
}
/// <summary>
@ -2608,7 +2674,6 @@ namespace IEC61850
return GetLogicalDeviceDataSetsAsync(null, ldName, continueAfter, handler, parameter);
}
public UInt32 GetLogicalDeviceDataSetsAsync(List<string> result, string ldName, string continueAfter, GetNameListHandler handler, object parameter)
{
int error;
@ -2953,6 +3018,19 @@ namespace IEC61850
IED_STATE_CLOSING = 3
}
public static class IedClientErrorExtension
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedClientError_toString(int err);
public static string ToString(this IedClientError err)
{
string stringVal = Marshal.PtrToStringAnsi(IedClientError_toString((int)err));
return stringVal;
}
}
/// <summary>
/// Error codes for client side functions
/// </summary>
@ -3038,6 +3116,9 @@ namespace IEC61850
/** Received an invalid response message from the server */
IED_ERROR_MALFORMED_MESSAGE = 34,
/** Service was not executed because required resource is still in use */
IED_ERROR_OBJECT_CONSTRAINT_CONFLICT = 35,
/** Service not implemented */
IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98,

@ -1,7 +1,7 @@
/*
* IEC61850CommonAPI.cs
*
* Copyright 2014-2017 Michael Zillgith
* Copyright 2014-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -454,6 +454,9 @@ namespace IEC61850
SetByMmsUtcTime (mmsUtcTime);
}
/// <summary>
/// Initializes a new instance of the <see cref="IEC61850CommonAPI.Timestamp"/> class.
/// </summary>
public Timestamp()
{
self = Timestamp_create ();
@ -461,6 +464,19 @@ namespace IEC61850
responsibleForDeletion = true;
}
/// <summary>
/// Initializes a new instance of the <see cref="IEC61850CommonAPI.Timestamp"/> class.
/// </summary>
public Timestamp(Timestamp other) : this()
{
SetTimeInSeconds (other.GetTimeInSeconds ());
SetSubsecondPrecision (other.GetSubsecondPrecision ());
SetFractionOfSecondPart (other.GetFractionOfSecondPart ());
SetLeapSecondKnow(other.IsLeapSecondKnown());
SetClockFailure(other.HasClockFailure());
SetClockNotSynchronized(other.IsClockNotSynchronized());
}
public Timestamp(byte[] value)
{
self = Timestamp_createFromByteArray (value);

@ -1,7 +1,7 @@
/*
* IEC61850ServerAPI.cs
*
* Copyright 2016-2022 Michael Zillgith
* Copyright 2016-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -1866,6 +1866,17 @@ namespace IEC61850
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ControlAction_isSelect(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ControlAction_getSynchroCheck(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool ControlAction_getInterlockCheck(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ControlAction_getT(IntPtr self);
private IntPtr self;
private IedServer.ControlHandlerInfo info;
private IedServer iedServer;
@ -1985,6 +1996,28 @@ namespace IEC61850
{
return ControlAction_isSelect(self);
}
public bool GetSynchroCheck()
{
return ControlAction_getSynchroCheck(self);
}
public bool GetInterlockCheck()
{
return ControlAction_getInterlockCheck(self);
}
/// <summary>
/// Gets the time (paramter T) of the control action
/// </summary>
public Timestamp GetT()
{
IntPtr tPtr = ControlAction_getT(self);
Timestamp t = new Timestamp(tPtr, false);
return new Timestamp(t);
}
}
public delegate void GoCBEventHandler(MmsGooseControlBlock goCB, int cbEvent, object parameter);
@ -2121,6 +2154,97 @@ namespace IEC61850
public delegate CheckHandlerResult CheckHandler (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck);
public static class SqliteLogStorage
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr SqliteLogStorage_createInstance(string filename);
public static LogStorage CreateLogStorage(string filename)
{
try
{
IntPtr nativeInstance = SqliteLogStorage_createInstance(filename);
if (nativeInstance != IntPtr.Zero)
return new LogStorage(nativeInstance);
else
return null;
}
catch (EntryPointNotFoundException ex)
{
Console.WriteLine(ex.Message + " Make sure that the libiec61850.dll was built with sqLite!");
return null;
}
}
}
public class LogStorage : IDisposable
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void LogStorage_setMaxLogEntries(IntPtr self, int maxEntries);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int LogStorage_getMaxLogEntries(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void LogStorage_destroy(IntPtr self);
private IntPtr self = IntPtr.Zero;
internal IntPtr GetNativeInstance()
{
return self;
}
internal LogStorage(IntPtr self)
{
this.self = self;
}
private void SetMaxLogEntries(int maxEntries)
{
LogStorage_setMaxLogEntries(self, maxEntries);
}
private int GetMaxLogEntries()
{
return LogStorage_getMaxLogEntries(self);
}
/// <summary>
/// The maximum allowed number of log entries in the log storage
/// </summary>
public int MaxLogEntries
{
get
{
return GetMaxLogEntries();
}
set
{
SetMaxLogEntries(value);
}
}
public void Dispose()
{
lock (this)
{
if (self != IntPtr.Zero)
{
LogStorage_destroy(self);
self = IntPtr.Zero;
}
}
}
~LogStorage()
{
Dispose();
}
}
/// <summary>
/// This class acts as the entry point for the IEC 61850 client API. It represents a single
/// (MMS) connection to a server.
@ -2229,6 +2353,10 @@ namespace IEC61850
static extern void IedServer_handleWriteAccessForComplexAttribute(IntPtr self, IntPtr dataAttribute,
InternalWriteAccessHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_handleWriteAccessForDataObject(IntPtr self, IntPtr dataObject, int fc,
InternalWriteAccessHandler handler, IntPtr parameter);
public delegate void ConnectionIndicationHandler(IedServer iedServer, ClientConnection clientConnection, bool connected, object parameter);
private ConnectionIndicationHandler connectionHandler = null;
@ -2273,6 +2401,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setRCBEventHandler(IntPtr self, InternalRCBEventHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setTimeQuality(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool leapSecondKnown, [MarshalAs(UnmanagedType.I1)] bool clockFailure, [MarshalAs(UnmanagedType.I1)] bool clockNotSynchronized, int subsecondPrecision);
private IntPtr self = IntPtr.Zero;
private InternalControlHandler internalControlHandlerRef = null;
@ -2280,6 +2411,9 @@ namespace IEC61850
private InternalControlWaitForExecutionHandler internalControlWaitForExecutionHandlerRef = null;
private InternalSelectStateChangedHandler internalSelectedStateChangedHandlerRef = null;
// hold references to managed LogStorage instances to avoid problems with GC
private Dictionary<string, LogStorage> logStorages = new Dictionary<string, LogStorage>();
internal class ControlHandlerInfo {
public DataObject controlObject = null;
public GCHandle handle;
@ -2435,6 +2569,9 @@ namespace IEC61850
/* store IedModel instance to prevent garbage collector */
private IedModel iedModel = null;
/* store TLSConfiguration instance to prevent garbage collector */
private TLSConfiguration tlsConfiguration = null;
public IedServer(IedModel iedModel, IedServerConfig config = null)
{
this.iedModel = iedModel;
@ -2450,6 +2587,7 @@ namespace IEC61850
public IedServer(IedModel iedModel, TLSConfiguration tlsConfig, IedServerConfig config = null)
{
this.iedModel = iedModel;
this.tlsConfiguration = tlsConfig;
IntPtr nativeConfig = IntPtr.Zero;
IntPtr nativeTLSConfig = IntPtr.Zero;
@ -2539,6 +2677,7 @@ namespace IEC61850
self = IntPtr.Zero;
internalConnectionHandler = null;
this.iedModel = null;
this.tlsConfiguration = null;
}
}
}
@ -2687,12 +2826,27 @@ namespace IEC61850
}
}
private void AddHandlerInfoForDataObjectRecursive(DataObject dataObject, FunctionalConstraint fc, WriteAccessHandler handler, object parameter, InternalWriteAccessHandler internalHandler)
{
foreach (ModelNode child in dataObject.GetChildren())
{
if (child is DataAttribute && (child as DataAttribute).FC == fc)
{
AddHandlerInfoForDataAttributeRecursive(child as DataAttribute, handler, parameter, internalHandler);
}
else if (child is DataObject)
{
AddHandlerInfoForDataObjectRecursive(child as DataObject, fc, handler, parameter, internalHandler);
}
}
}
/// <summary>
/// Install a WriteAccessHandler for a data attribute and for all sub data attributes
/// </summary>
/// This instructs the server to monitor write attempts by MMS clients to specific
/// data attributes.If a client tries to write to the monitored data attribute the
/// handler is invoked.The handler can decide if the write access will be allowed
/// data attributes. If a client tries to write to the monitored data attribute the
/// handler is invoked. The handler can decide if the write access will be allowed
/// or denied.If a WriteAccessHandler is set for a specific data attribute - the
/// default write access policy will not be performed for that data attribute.
/// <remarks>
@ -2712,6 +2866,27 @@ namespace IEC61850
IedServer_handleWriteAccessForComplexAttribute(self, dataAttr.self, internalHandler, IntPtr.Zero);
}
/// <summary>
/// Install a WriteAccessHandler for a data object and for all sub data objects and sub data attributes that have the same functional constraint
/// </summary>
/// This instructs the server to monitor write attempts by MMS clients to specific
/// data attributes. If a client tries to write to the monitored data attribute the
/// handler is invoked. The handler can decide if the write access will be allowed
/// or denied. If a WriteAccessHandler is set the
/// default write access policy will not be performed for the matching data attributes.
/// <param name="dataObject">the data object to monitor</param>
/// <param name="fc">the functional constraint (FC) to monitor</param>
/// <param name="handler">the callback function that is invoked if a client tries to write to a monitored data attribute that is a child of the data object.</param>
/// <param name="parameter">a user provided parameter that is passed to the WriteAccessHandler when called.</param>
public void HandleWriteAccessForDataObject(DataObject dataObj, FunctionalConstraint fc, WriteAccessHandler handler, object parameter)
{
InternalWriteAccessHandler internalHandler = new InternalWriteAccessHandler(WriteAccessHandlerImpl);
AddHandlerInfoForDataObjectRecursive(dataObj, fc, handler, parameter, internalHandler);
IedServer_handleWriteAccessForDataObject(self, dataObj.self, (int)fc, internalHandler, IntPtr.Zero);
}
/// <summary>
/// Set the defualt write access policy for a specific FC. The default policy is applied when no handler is installed for a data attribute
/// </summary>
@ -2996,7 +3171,29 @@ namespace IEC61850
}
}
}
/// <summary>
/// Set the time quality for all timestamps internally generated by this IedServer instance
/// </summary>
/// <param name="leapSecondKnown">set/unset leap seconds known flag</param>
/// <param name="clockFailure">set/unset clock failure flag</param>
/// <param name="clockNotSynchronized">set/unset clock not synchronized flag</param>
/// <param name="subsecondPrecision">set the subsecond precision (number of significant bits of the fractionOfSecond part of the time stamp)</param>
public void SetTimeQuality(bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision)
{
IedServer_setTimeQuality(self, leapSecondKnown, clockFailure, clockNotSynchronized, subsecondPrecision);
}
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setLogStorage(IntPtr self, string logRef, IntPtr logStorage);
public void SetLogStorage(string logRef, LogStorage logStorage)
{
if (logStorage != null)
{
logStorages.Add(logRef, logStorage);
IedServer_setLogStorage(self, logRef, logStorage.GetNativeInstance());
}
}
}
}
}

@ -27,6 +27,21 @@ using IEC61850.Common;
namespace IEC61850.Server
{
/// <summary>
/// RCB properties that are configurable to be writable or read-only
/// </summary>
[Flags]
public enum ReportSettings
{
RPT_ID = 1,
BUF_TIME = 2,
DATSET = 4,
TRG_OPS = 8,
OPT_FIELDS = 16,
INTG_PD = 32,
}
/// <summary>
/// IedServer configuration object
/// </summary>
@ -131,6 +146,13 @@ namespace IEC61850.Server
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setSyncIntegrityReportTimes(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServerConfig_setReportSetting(IntPtr self, byte setting, [MarshalAs(UnmanagedType.I1)] bool enable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool IedServerConfig_getReportSetting(IntPtr self, byte setting);
internal IntPtr self;
public IedServerConfig()
@ -379,6 +401,28 @@ namespace IEC61850.Server
}
}
/// <summary>
/// Make a configurable report setting writeable or read-only
/// </summary>
/// <note><c>ReportSettings</c> is a flag enum, so you can set multiple settings at once</note>
/// <note>Can be used to implement some of Services\ReportSettings options</note>
/// <param name="settings">the settings that should be configured writeable or read-only</param>
/// <param name="isDyn">true, settings are writeable, false, settings are read-only</param>
public void SetReportSetting(ReportSettings settings, bool isDyn = true)
{
IedServerConfig_setReportSetting(self, (byte)settings, isDyn);
}
/// <summary>
/// Get the value of a specific report setting
/// </summary>
/// <param name="setting">one value of <c>ReportSettings</c></param>
/// <returns>true, when setting is writable ("Dyn") or false, when read-only</returns>
public bool GetReportSetting(ReportSettings setting)
{
return IedServerConfig_getReportSetting(self, (byte)setting);
}
/// <summary>
/// Releases all resource used by the <see cref="IEC61850.Server.IedServerConfig"/> object.
/// </summary>

@ -1,7 +1,7 @@
/*
* MmsVariableSpecification.cs
*
* Copyright 2014 Michael Zillgith
* Copyright 2014-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -30,58 +30,58 @@ using System.Text;
namespace IEC61850
{
namespace Common
{
namespace Common
{
/// <summary>
/// MMS variable specification. This class is used to represent an MMS variable type definition.
/// </summary>
public class MmsVariableSpecification : IEnumerable
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void MmsVariableSpecification_destroy(IntPtr self);
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_getNamedVariableRecursive(IntPtr variable, string nameId);
[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 int MmsVariableSpecification_getType(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsVariableSpecification_getName(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 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_getChildSpecificationByIndex(IntPtr self, int index);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsVariableSpecification_getArrayElementSpecification(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsVariableSpecification_getArrayElementSpecification(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int MmsVariableSpecification_getExponentWidth(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int MmsVariableSpecification_getExponentWidth(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern bool MmsVariableSpecification_isValueOfType(IntPtr self, IntPtr value);
internal IntPtr self;
private bool responsableForDeletion;
internal IntPtr self;
private bool responsableForDeletion;
/* only to prevent garbage collector to destroy parent element */
internal MmsVariableSpecification parent = null;
internal MmsVariableSpecification (IntPtr self, MmsVariableSpecification parent)
{
this.self = self;
this.responsableForDeletion = false;
internal MmsVariableSpecification(IntPtr self, MmsVariableSpecification parent)
{
this.self = self;
this.responsableForDeletion = false;
this.parent = parent;
}
}
internal MmsVariableSpecification (IntPtr self, bool responsableForDeletion)
{
this.self = self;
this.responsableForDeletion = responsableForDeletion;
}
internal MmsVariableSpecification(IntPtr self, bool responsableForDeletion)
{
this.self = self;
this.responsableForDeletion = responsableForDeletion;
}
/// <summary>
/// Get a child variable specification by its name
@ -104,11 +104,11 @@ namespace IEC61850
return null;
}
~MmsVariableSpecification ()
{
if (responsableForDeletion)
MmsVariableSpecification_destroy(self);
}
~MmsVariableSpecification()
{
if (responsableForDeletion)
MmsVariableSpecification_destroy(self);
}
/// <summary>
/// Gets the MmsValue type of the variable
@ -116,10 +116,18 @@ namespace IEC61850
/// <returns>
/// The MmsType of the variable
/// </returns>
public new MmsType GetType ()
{
return (MmsType) MmsVariableSpecification_getType(self);
}
public new MmsType GetType()
{
return (MmsType)MmsVariableSpecification_getType(self);
}
/// <summary>
/// The MmsValue type of the variable
/// </summary>
public MmsType MmsType
{
get { return (MmsType)MmsVariableSpecification_getType(self); }
}
/// <summary>
/// Gets the type of the array elements.
@ -128,15 +136,33 @@ namespace IEC61850
/// The array element type.
/// </returns>
/// <exception cref="MmsValueException">This exception is thrown if the value is not of type MMS_ARRAY</exception>
public MmsVariableSpecification getArrayElementType ()
{
if (GetType() == MmsType.MMS_ARRAY) {
IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self);
return new MmsVariableSpecification(varSpecPtr, this);
}
else
throw new MmsValueException ("specification is of wrong type");
}
public MmsVariableSpecification getArrayElementType()
{
if (GetType() == MmsType.MMS_ARRAY)
{
IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self);
return new MmsVariableSpecification(varSpecPtr, this);
}
else
throw new MmsValueException("specification is of wrong type");
}
/// <summary>
/// The type of array elements (when the variable is of type MMS_ARRAY)
/// </summary>
public MmsVariableSpecification ArrayElementType
{
get
{
if (GetType() == MmsType.MMS_ARRAY)
{
IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self);
return new MmsVariableSpecification(varSpecPtr, this);
}
else
return null;
}
}
/// <summary>
/// Gets the element specification of a structure element
@ -147,41 +173,86 @@ namespace IEC61850
/// <param name='index'>
/// Index.
/// </param>
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, this);
}
else
throw new MmsValueException ("Index out of bounds");
}
else
throw new MmsValueException ("specification is of wrong type");
}
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, this);
}
else
throw new MmsValueException("Index out of bounds");
}
else
throw new MmsValueException("specification is of wrong type");
}
/// <summary>
/// Gets the name of the variable
/// The element types for complex variables (MMS_STRUCTURE)
/// </summary>
public MmsVariableSpecification[] Elements
{
get
{
if (GetType() != MmsType.MMS_STRUCTURE)
return null;
List<MmsVariableSpecification> elements = new List<MmsVariableSpecification>();
for (int i = 0; i < Size(); i++)
{
elements.Add(GetElement(i));
}
return elements.ToArray();
}
}
/// <summary>
/// Gets the name of the variable (relative to the parent)
/// </summary>
/// <returns>
/// The name.
/// </returns>
public string GetName ()
{
IntPtr namePtr = MmsVariableSpecification_getName(self);
public string GetName()
{
IntPtr namePtr = MmsVariableSpecification_getName(self);
return Marshal.PtrToStringAnsi(namePtr);
}
return Marshal.PtrToStringAnsi (namePtr);
}
/// <summary>
/// The name of the variable (relative to the parent)
/// </summary>
public string Name
{
get
{
return GetName();
}
}
/// <summary>
/// Get the "size" of the variable (array size, number of structure elements ...)
/// </summary>
public int Size ()
{
return MmsVariableSpecification_getSize(self);
}
public int Size()
{
return MmsVariableSpecification_getSize(self);
}
/// <summary>
/// The "size" of the variable (array size, number of structure elements ...)
/// </summary>
public int size
{
get
{
return MmsVariableSpecification_getSize(self);
}
}
/// <summary>
/// Determines whether the given value object matches this type
@ -193,45 +264,46 @@ namespace IEC61850
return MmsVariableSpecification_isValueOfType(self, value.valueReference);
}
IEnumerator IEnumerable.GetEnumerator ()
{
return new MmsVariableSpecificationEnumerator (this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new MmsVariableSpecificationEnumerator(this);
}
private class MmsVariableSpecificationEnumerator : IEnumerator
{
private MmsVariableSpecification value;
private int index = -1;
private class MmsVariableSpecificationEnumerator : IEnumerator
{
private MmsVariableSpecification value;
private int index = -1;
public MmsVariableSpecificationEnumerator (MmsVariableSpecification value)
{
this.value = value;
}
public MmsVariableSpecificationEnumerator(MmsVariableSpecification value)
{
this.value = value;
}
#region IEnumerator Members
public void Reset ()
{
index = -1;
}
#region IEnumerator Members
public void Reset()
{
index = -1;
}
public object Current {
public object Current
{
get { return value.GetElement (index);}
}
get { return value.GetElement(index); }
}
public bool MoveNext ()
{
index++;
public bool MoveNext()
{
index++;
if (index >= value.Size ())
return false;
else
return true;
}
if (index >= value.Size())
return false;
else
return true;
}
#endregion
}
#endregion
}
}
}
}
}
}

@ -1,7 +1,7 @@
/*
* TLS.cs
*
* Copyright 2017 Michael Zillgith
* Copyright 2017-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -35,181 +35,461 @@ using IEC61850.Common;
/// </summary>
namespace IEC61850
{
namespace TLS
{
/// <summary>
/// A container for TLS configuration and certificates.
/// </summary>
public class TLSConfiguration : IDisposable
{
private IntPtr self = IntPtr.Zero;
private bool allowOnlyKnownCerts = false;
private bool chainValidation = true;
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr TLSConfiguration_create();
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_destroy(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setAllowOnlyKnownCertificates(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setChainValidation (IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setClientMode(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnCertificate(IntPtr self, byte[] certificate, int certLen);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnCertificateFromFile(IntPtr self, string filename);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnKey(IntPtr self, byte[] key, int keyLen, string keyPassword);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnKeyFromFile (IntPtr self, string filename, string keyPassword);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addAllowedCertificate(IntPtr self, byte[] certificate, int certLen);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addAllowedCertificateFromFile(IntPtr self, string filename);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addCACertificate(IntPtr self, byte[] certificate, int certLen);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addCACertificateFromFile(IntPtr self, string filename);
public TLSConfiguration() {
self = TLSConfiguration_create ();
}
~TLSConfiguration()
{
Dispose ();
}
internal IntPtr GetNativeInstance()
{
return self;
}
public bool AllowOnlyKnownCertificates
{
set {
TLSConfiguration_setAllowOnlyKnownCertificates (self, value);
allowOnlyKnownCerts = value;
}
get {
return allowOnlyKnownCerts;
}
}
public bool ChainValidation
{
set {
TLSConfiguration_setChainValidation (self, value);
chainValidation = value;
}
get {
return chainValidation;
}
}
public void SetClientMode()
{
TLSConfiguration_setClientMode (self);
}
public void SetOwnCertificate(string filename)
{
if (TLSConfiguration_setOwnCertificateFromFile (self, filename) == false) {
throw new CryptographicException ("Failed to read certificate from file");
}
}
public void SetOwnCertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_setOwnCertificate (self, certBytes, certBytes.Length) == false) {
throw new CryptographicException ("Failed to set certificate");
}
}
public void AddAllowedCertificate(string filename)
{
if (TLSConfiguration_addAllowedCertificateFromFile (self, filename) == false) {
throw new CryptographicException ("Failed to read allowed certificate from file");
}
}
public void AddAllowedCertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_addAllowedCertificate (self, certBytes, certBytes.Length) == false) {
throw new CryptographicException ("Failed to add allowed certificate");
}
}
public void AddCACertificate(string filename)
{
if (TLSConfiguration_addCACertificateFromFile (self, filename) == false) {
throw new CryptographicException ("Failed to read CA certificate from file");
}
}
public void AddCACertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData ();
if (TLSConfiguration_addCACertificate (self, certBytes, certBytes.Length) == false) {
throw new CryptographicException ("Failed to add CA certificate");
}
}
public void SetOwnKey (string filename, string password)
{
if (TLSConfiguration_setOwnKeyFromFile (self, filename, password) == false) {
throw new CryptographicException ("Failed to read own key from file");
}
}
public void SetOwnKey (X509Certificate2 key, string password)
{
byte[] certBytes = key.Export (X509ContentType.Pkcs12);
if (TLSConfiguration_setOwnKey (self, certBytes, certBytes.Length, password) == false) {
throw new CryptographicException ("Failed to set own key");
}
}
public void Dispose()
{
lock (this) {
if (self != IntPtr.Zero) {
TLSConfiguration_destroy (self);
self = IntPtr.Zero;
}
}
}
}
}
}
namespace TLS
{
public enum TLSConfigVersion
{
NOT_SELECTED = 0,
SSL_3_0 = 3,
TLS_1_0 = 4,
TLS_1_1 = 5,
TLS_1_2 = 6,
TLS_1_3 = 7
}
public enum TLSEventLevel
{
INFO = 0,
WARNING = 1,
INCIDENT = 2
}
public enum TLSEventCode
{
ALM_ALGO_NOT_SUPPORTED = 1,
ALM_UNSECURE_COMMUNICATION = 2,
ALM_CERT_UNAVAILABLE = 3,
ALM_BAD_CERT = 4,
ALM_CERT_SIZE_EXCEEDED = 5,
ALM_CERT_VALIDATION_FAILED = 6,
ALM_CERT_REQUIRED = 7,
ALM_HANDSHAKE_FAILED_UNKNOWN_REASON = 8,
WRN_INSECURE_TLS_VERSION = 9,
INF_SESSION_RENEGOTIATION = 10,
ALM_CERT_EXPIRED = 11,
ALM_CERT_REVOKED = 12,
ALM_CERT_NOT_CONFIGURED = 13,
ALM_CERT_NOT_TRUSTED = 14,
ALM_NO_CIPHER = 15,
INF_SESSION_ESTABLISHED = 16
}
public class TLSConnection
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int TLSConnection_getTLSVersion(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr TLSConnection_getPeerAddress(IntPtr self, IntPtr peerAddrBuf);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr TLSConnection_getPeerCertificate(IntPtr self, out int certSize);
private IntPtr self;
private bool isValid;
internal TLSConnection(IntPtr self)
{
this.self = self;
isValid = true;
}
// To be called by event callback caller after callback execution
internal void InValidate()
{
lock (this)
{
isValid = false;
}
}
/// <summary>
/// TLS version used by the connection
/// </summary>
public TLSConfigVersion TLSVersion
{
get
{
lock (this)
{
if (isValid)
{
return (TLSConfigVersion)TLSConnection_getTLSVersion((IntPtr)self);
}
else
{
throw new InvalidOperationException("Object cannot be used outside of TLS event callback");
}
}
}
}
/// <summary>
/// Peer IP address and TCP port of the TLS connection
/// </summary>
public string PeerAddress
{
get
{
lock (this)
{
if (isValid)
{
IntPtr peerAddrBuf = Marshal.AllocHGlobal(130);
IntPtr peerAddrStr = TLSConnection_getPeerAddress(this.self, peerAddrBuf);
string peerAddr = null;
if (peerAddrStr != IntPtr.Zero)
{
peerAddr = Marshal.PtrToStringAnsi(peerAddrStr);
}
Marshal.FreeHGlobal(peerAddrBuf);
return peerAddr;
}
else
{
throw new InvalidOperationException("Object cannot be used outside of TLS event callback");
}
}
}
}
/// <summary>
/// TLS certificate used by the peer
/// </summary>
public byte[] PeerCertificate
{
get
{
lock (this)
{
if (isValid)
{
int certSize;
IntPtr certBuffer = TLSConnection_getPeerCertificate(self, out certSize);
if (certBuffer != IntPtr.Zero)
{
if (certSize > 0)
{
byte[] cert = new byte[certSize];
Marshal.Copy(certBuffer, cert, 0, certSize);
return cert;
}
}
return null;
}
else
{
throw new InvalidOperationException("Object cannot be used outside of TLS event callback");
}
}
}
}
}
/// <summary>
/// TLS security event handler
/// </summary>
/// <param name="parameter">user provided context paramter to be passed to the handler</param>
/// <param name="eventLevel">severity level of the event</param>
/// <param name="eventCode">code to identify the event type</param>
/// <param name="message">text message describing the event</param>
/// <param name="connection">TLS connection that caused the event</param>
public delegate void TLSEventHandler(object parameter, TLSEventLevel eventLevel, TLSEventCode eventCode, string message, TLSConnection connection);
/// <summary>
/// A container for TLS configuration and certificates.
/// </summary>
public class TLSConfiguration : IDisposable
{
private IntPtr self = IntPtr.Zero;
private bool allowOnlyKnownCerts = false;
private bool chainValidation = true;
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr TLSConfiguration_create();
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_destroy(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setAllowOnlyKnownCertificates(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setChainValidation(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setClientMode(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnCertificate(IntPtr self, byte[] certificate, int certLen);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnCertificateFromFile(IntPtr self, string filename);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnKey(IntPtr self, byte[] key, int keyLen, string keyPassword);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_setOwnKeyFromFile(IntPtr self, string filename, string keyPassword);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addAllowedCertificate(IntPtr self, byte[] certificate, int certLen);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addAllowedCertificateFromFile(IntPtr self, string filename);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addCACertificate(IntPtr self, byte[] certificate, int certLen);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool TLSConfiguration_addCACertificateFromFile(IntPtr self, string filename);
[DllImport("tase2", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setMinTlsVersion(IntPtr self, int version);
[DllImport("tase2", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setMaxTlsVersion(IntPtr self, int version);
[DllImport("tase2", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_addCipherSuite(IntPtr self, int ciphersuite);
[DllImport("tase2", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_clearCipherSuiteList(IntPtr self);
private TLSEventHandler eventHandler = null;
private object eventHandlerParameter = null;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void InternalTLSEventHandler(IntPtr parameter, int eventLevel, int eventCode, IntPtr message, IntPtr tlsCon);
private InternalTLSEventHandler internalTLSEventHandlerRef = null;
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void TLSConfiguration_setEventHandler(IntPtr self, InternalTLSEventHandler handler, IntPtr parameter);
void InternalTLSEventHandlerImpl(IntPtr parameter, int eventLevel, int eventCode, IntPtr message, IntPtr tlsCon)
{
if (eventHandler != null)
{
TLSConnection connection = new TLSConnection(tlsCon);
string msg = Marshal.PtrToStringAnsi(message);
eventHandler(eventHandlerParameter, (TLSEventLevel)eventLevel, (TLSEventCode)eventCode, msg, connection);
connection.InValidate();
}
}
public void SetEventHandler(TLSEventHandler handler, object parameter)
{
this.eventHandler = handler;
this.eventHandlerParameter = parameter;
if (internalTLSEventHandlerRef == null)
{
internalTLSEventHandlerRef = new InternalTLSEventHandler(InternalTLSEventHandlerImpl);
TLSConfiguration_setEventHandler(self, internalTLSEventHandlerRef, IntPtr.Zero);
}
}
public TLSConfiguration()
{
self = TLSConfiguration_create();
}
~TLSConfiguration()
{
Dispose();
}
internal IntPtr GetNativeInstance()
{
return self;
}
public bool AllowOnlyKnownCertificates
{
set
{
TLSConfiguration_setAllowOnlyKnownCertificates(self, value);
allowOnlyKnownCerts = value;
}
get
{
return allowOnlyKnownCerts;
}
}
public bool ChainValidation
{
set
{
TLSConfiguration_setChainValidation(self, value);
chainValidation = value;
}
get
{
return chainValidation;
}
}
public void SetClientMode()
{
TLSConfiguration_setClientMode(self);
}
public void SetOwnCertificate(string filename)
{
if (TLSConfiguration_setOwnCertificateFromFile(self, filename) == false)
{
throw new CryptographicException("Failed to read certificate from file");
}
}
public void SetOwnCertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData();
if (TLSConfiguration_setOwnCertificate(self, certBytes, certBytes.Length) == false)
{
throw new CryptographicException("Failed to set certificate");
}
}
public void AddAllowedCertificate(string filename)
{
if (TLSConfiguration_addAllowedCertificateFromFile(self, filename) == false)
{
throw new CryptographicException("Failed to read allowed certificate from file");
}
}
public void AddAllowedCertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData();
if (TLSConfiguration_addAllowedCertificate(self, certBytes, certBytes.Length) == false)
{
throw new CryptographicException("Failed to add allowed certificate");
}
}
public void AddCACertificate(string filename)
{
if (TLSConfiguration_addCACertificateFromFile(self, filename) == false)
{
throw new CryptographicException("Failed to read CA certificate from file");
}
}
public void AddCACertificate(X509Certificate2 cert)
{
byte[] certBytes = cert.GetRawCertData();
if (TLSConfiguration_addCACertificate(self, certBytes, certBytes.Length) == false)
{
throw new CryptographicException("Failed to add CA certificate");
}
}
public void SetOwnKey(string filename, string password)
{
if (TLSConfiguration_setOwnKeyFromFile(self, filename, password) == false)
{
throw new CryptographicException("Failed to read own key from file");
}
}
public void SetOwnKey(X509Certificate2 key, string password)
{
byte[] certBytes = key.Export(X509ContentType.Pkcs12);
if (TLSConfiguration_setOwnKey(self, certBytes, certBytes.Length, password) == false)
{
throw new CryptographicException("Failed to set own key");
}
}
/// <summary>
/// Set minimal allowed TLS version to use
/// </summary>
/// <param name="version">lowest allowed TLS version</param>
public void SetMinTlsVersion(TLSConfigVersion version)
{
TLSConfiguration_setMinTlsVersion(self, (int)version);
}
/// <summary>
/// Set highest allowed TLS version to use
/// </summary>
/// <param name="version">highest allowed TLS version</param>
public void SetMaxTlsVersion(TLSConfigVersion version)
{
TLSConfiguration_setMaxTlsVersion(self, (int)version);
}
#if NET
/// <summary>
/// Add an allowed ciphersuite to the list of allowed ciphersuites
/// </summary>
/// <param name="ciphersuite"></param>
public void addCipherSuite(TlsCipherSuite ciphersuite)
{
TLSConfiguration_addCipherSuite(self,(int) ciphersuite);
}
#endif
/// <summary>
/// Add an allowed ciphersuite to the list of allowed ciphersuites
/// </summary>
/// <remarks>Version for .NET framework that does not support TlsCipherSuite enum</remarks>
/// <param name="ciphersuite"></param>
public void addCipherSuite(int ciphersuite)
{
TLSConfiguration_addCipherSuite(self, ciphersuite);
}
/// <summary>
/// Clears list of allowed ciphersuites
/// </summary>
/// <returns></returns>
public void clearCipherSuiteList()
{
TLSConfiguration_clearCipherSuiteList(self);
}
public void Dispose()
{
lock (this)
{
if (self != IntPtr.Zero)
{
TLSConfiguration_destroy(self);
self = IntPtr.Zero;
}
}
}
}
}
}

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>authenticate</RootNamespace>
<AssemblyName>authenticate</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>client_example_async</RootNamespace>
<AssemblyName>client_example_async</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -28,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>clientexamplesettinggroup</RootNamespace>
<AssemblyName>client-example-setting-group</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -41,4 +42,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>control</RootNamespace>
<AssemblyName>control</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>datasets</RootNamespace>
<AssemblyName>datasets</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.779
# Visual Studio Version 17
VisualStudioVersion = 17.10.35004.147
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
EndProject
@ -50,6 +50,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_async", "cli
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server_goose_publisher", "server_goose_publisher\server_goose_publisher.csproj", "{C14BB883-86B8-401C-B3D6-B655F55F3298}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "log_server", "log_server\log_server.csproj", "{96124F40-D38E-499B-9968-674E0D32F933}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -140,6 +142,10 @@ Global
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C14BB883-86B8-401C-B3D6-B655F55F3298}.Release|Any CPU.Build.0 = Release|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>example1</RootNamespace>
<AssemblyName>example1</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -36,7 +36,7 @@ namespace example2
}
catch (IedConnectionException e)
{
Console.WriteLine("IED connection excepion: " + e.Message);
Console.WriteLine("IED connection exception: " + e.Message + " err: " + e.GetIedClientError().ToString());
}
// release all resources - do NOT use the object after this call!!

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>example2</RootNamespace>
<AssemblyName>example2</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>example3</RootNamespace>
<AssemblyName>example3</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>files</RootNamespace>
<AssemblyName>files</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>goose_subscriber</RootNamespace>
<AssemblyName>goose_subscriber</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -41,4 +42,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>log_client</RootNamespace>
<AssemblyName>log_client</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -18,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
@ -26,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -41,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
</Project>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>

@ -0,0 +1,91 @@
using IEC61850.Common;
using IEC61850.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace log_server
{
internal class Program
{
public static void Main(string[] args)
{
bool running = true;
/* run until Ctrl-C is pressed */
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
running = false;
};
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("model.cfg");
if (iedModel == null)
{
Console.WriteLine("No valid data model found!");
return;
}
IedServerConfig config = new IedServerConfig();
config.ReportBufferSize = 100000;
IedServer iedServer = new IedServer(iedModel, config);
LogStorage statusLog = SqliteLogStorage.CreateLogStorage("log_status.db");
statusLog.MaxLogEntries = 10;
iedServer.SetLogStorage("GenericIO/LLN0$EventLog", statusLog);
iedServer.Start(10002);
if (iedServer.IsRunning())
{
Console.WriteLine("Server started");
DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1");
DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild("mag.f");
DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild("t");
DataObject ggio1Spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO1");
DataAttribute ggio1Spcso1stVal = (DataAttribute)ggio1Spcso1.GetChild("stVal");
DataAttribute ggio1Spcso1T = (DataAttribute)ggio1Spcso1.GetChild("t");
float floatVal = 1.0f;
bool stVal = true;
while (running)
{
floatVal += 1f;
stVal = !stVal;
iedServer.LockDataModel();
var ts = new Timestamp(DateTime.Now);
iedServer.UpdateTimestampAttributeValue(ggio1AnIn1T, ts);
iedServer.UpdateFloatAttributeValue(ggio1AnIn1magF, floatVal);
iedServer.UpdateTimestampAttributeValue(ggio1Spcso1T, ts);
iedServer.UpdateBooleanAttributeValue(ggio1Spcso1stVal, stVal);
iedServer.UnlockDataModel();
Thread.Sleep(100);
}
iedServer.Stop();
Console.WriteLine("Server stopped");
}
else
{
Console.WriteLine("Failed to start server");
}
iedServer.Destroy();
}
}
}

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("log_server")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("log_server")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("96124f40-d38e-499b-9968-674e0d32f933")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{96124F40-D38E-499B-9968-674E0D32F933}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>log_server</RootNamespace>
<AssemblyName>log_server</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="model.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850.NET.csproj">
<Project>{C35D624E-5506-4560-8074-1728F1FA1A4D}</Project>
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.8.1">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.8.1 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,237 @@
MODEL(simpleIO){
LD(GenericIO){
LN(LLN0){
DO(Mod 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=0;
}
DO(Beh 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Health 0){
DA(stVal 0 3 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(NamPlt 0){
DA(vendor 0 20 5 0 0);
DA(swRev 0 20 5 0 0);
DA(d 0 20 5 0 0);
DA(configRev 0 20 5 0 0);
DA(ldNs 0 20 11 0 0);
}
DS(Events){
DE(GGIO1$ST$SPCSO1$stVal);
DE(GGIO1$ST$SPCSO2$stVal);
DE(GGIO1$ST$SPCSO3$stVal);
DE(GGIO1$ST$SPCSO4$stVal);
}
DS(AnalogValues){
DE(GGIO1$MX$AnIn1);
DE(GGIO1$MX$AnIn2);
DE(GGIO1$MX$AnIn3);
DE(GGIO1$MX$AnIn4);
}
RC(EventsRCB01 Events 0 Events 1 24 111 50 1000);
RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 111 50 1000);
LC(EventLog Events GenericIO/LLN0$EventLog 19 0 0 1);
LC(GeneralLog - - 19 0 0 1);
LOG(GeneralLog);
LOG(EventLog);
GC(gcbEvents events Events 2 0 -1 -1 ){
PA(4 273 4096 010ccd010001);
}
GC(gcbAnalogValues analog AnalogValues 2 0 -1 -1 ){
PA(4 273 4096 010ccd010001);
}
}
LN(LPHD1){
DO(PhyNam 0){
DA(vendor 0 20 5 0 0);
}
DO(PhyHealth 0){
DA(stVal 0 3 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Proxy 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
}
LN(GGIO1){
DO(Mod 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=0;
}
DO(Beh 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Health 0){
DA(stVal 0 3 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(NamPlt 0){
DA(vendor 0 20 5 0 0);
DA(swRev 0 20 5 0 0);
DA(d 0 20 5 0 0);
}
DO(AnIn1 0){
DA(mag 0 27 1 1 0){
DA(f 0 10 1 1 0);
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
DO(AnIn2 0){
DA(mag 0 27 1 1 101){
DA(f 0 10 1 1 0);
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 102);
}
DO(AnIn3 0){
DA(mag 0 27 1 1 0){
DA(f 0 10 1 1 0);
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
DO(AnIn4 0){
DA(mag 0 27 1 1 0){
DA(f 0 10 1 1 0);
}
DA(q 0 23 1 2 0);
DA(t 0 22 1 0 0);
}
DO(SPCSO1 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
DA(orCat 0 12 12 0 0);
DA(orIdent 0 13 12 0 0);
}
DA(ctlNum 0 6 12 0 0);
DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(ctlModel 0 12 4 0 0)=1;
DA(t 0 22 0 0 0);
}
DO(SPCSO2 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
DA(orCat 0 12 12 0 0);
DA(orIdent 0 13 12 0 0);
}
DA(ctlNum 0 6 12 0 0);
DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(ctlModel 0 12 4 0 0)=1;
DA(t 0 22 0 0 0);
}
DO(SPCSO3 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
DA(orCat 0 12 12 0 0);
DA(orIdent 0 13 12 0 0);
}
DA(ctlNum 0 6 12 0 0);
DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(ctlModel 0 12 4 0 0)=1;
DA(t 0 22 0 0 0);
}
DO(SPCSO4 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(Oper 0 27 12 0 0){
DA(ctlVal 0 0 12 0 0);
DA(origin 0 27 12 0 0){
DA(orCat 0 12 12 0 0);
DA(orIdent 0 13 12 0 0);
}
DA(ctlNum 0 6 12 0 0);
DA(T 0 22 12 0 0);
DA(Test 0 0 12 0 0);
DA(Check 0 24 12 0 0);
}
DA(ctlModel 0 12 4 0 0)=1;
DA(t 0 22 0 0 0);
}
DO(Ind1 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Ind2 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Ind3 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Ind4 0){
DA(stVal 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
}
LN(PDUP1){
DO(Beh 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Mod 0){
DA(stVal 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
DA(ctlModel 0 12 4 0 0)=0;
}
DO(Str 0){
DA(general 0 0 0 1 0);
DA(dirGeneral 0 12 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(Op 0){
DA(general 0 0 0 1 0);
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
}
DO(OpDlTmms 0){
DA(setVal 0 3 2 1 0);
}
DO(RsDlTmms 0){
DA(setVal 0 3 2 1 0);
}
}
}
}

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>model_browsing</RootNamespace>
<AssemblyName>model_browsing</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>report_new_dataset</RootNamespace>
<AssemblyName>report_new_dataset</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -40,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -22,6 +22,8 @@
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -33,6 +35,7 @@
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<UseVSHostingProcess>true</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -41,6 +44,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -78,4 +82,7 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
</Project>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>server1</RootNamespace>
<AssemblyName>server1</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -28,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -44,6 +45,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="model.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>sv_subscriber</RootNamespace>
<AssemblyName>sv_subscriber</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -19,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>
@ -27,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -42,4 +44,7 @@
<Name>IEC61850.NET</Name>
</ProjectReference>
</ItemGroup>
</Project>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
</Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,6 +7,8 @@
<OutputType>Library</OutputType>
<RootNamespace>tests</RootNamespace>
<AssemblyName>tests</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -17,6 +19,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -25,6 +28,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Compile Include="Test.cs" />

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>tls_client_example</RootNamespace>
<AssemblyName>tls_client_example</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -42,6 +43,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="client1.cer">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -7,7 +7,8 @@
<OutputType>Exe</OutputType>
<RootNamespace>tls_server_example</RootNamespace>
<AssemblyName>tls_server_example</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -42,6 +43,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="server-key.pem">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

@ -14,6 +14,7 @@ add_subdirectory(server_example_files)
add_subdirectory(server_example_substitution)
add_subdirectory(server_example_service_tracking)
add_subdirectory(server_example_deadband)
add_subdirectory(server_example_access_control)
add_subdirectory(iec61850_client_example1)
add_subdirectory(iec61850_client_example2)
@ -26,6 +27,9 @@ add_subdirectory(iec61850_client_example_array)
add_subdirectory(iec61850_client_example_files)
add_subdirectory(iec61850_client_example_async)
add_subdirectory(iec61850_client_file_async)
add_subdirectory(iec61850_client_example_rcbAsync)
add_subdirectory(iec61850_client_example_ClientGooseControl)
add_subdirectory(iec61850_client_example_ClientGooseControlAsync)
if (${BUILD_SNTP_CLIENT_EXAMPLES})
add_subdirectory(sntp_example)
@ -54,10 +58,10 @@ else()
set(BUILD_SV_GOOSE_EXAMPLES ON)
endif()
if(WITH_MBEDTLS)
if(WITH_MBEDTLS OR WITH_MBEDTLS3)
add_subdirectory(tls_client_example)
add_subdirectory(tls_server_example)
endif(WITH_MBEDTLS)
endif(WITH_MBEDTLS OR WITH_MBEDTLS3)
if(${BUILD_SV_GOOSE_EXAMPLES})
add_subdirectory(server_example_goose)

@ -29,6 +29,9 @@ EXAMPLE_DIRS += iec61850_9_2_LE_example
EXAMPLE_DIRS += iec61850_sv_client_example
EXAMPLE_DIRS += sv_publisher
EXAMPLE_DIRS += sv_subscriber
EXAMPLE_DIRS += iec61850_client_example_rcbAsync
EXAMPLE_DIRS += iec61850_client_example_ClientGooseControl
EXAMPLE_DIRS += iec61850_client_example_ClientGooseControlAsync
MODEL_DIRS += server_example_simple
MODEL_DIRS += server_example_basic_io

@ -93,7 +93,7 @@ SCL.xsd">
</DataSet>
<SampledValueControl name="MSVCB01" datSet="PhsMeas1"
smvID="xxxxMUnn01" smpRate="80" nofASDU="1" confRev="1">
smvID="xxxxMUnn01" smpRate="80" nofASDU="1" confRev="1" smpMod="SmpPerPeriod">
<SmvOpts refreshTime="false" sampleSynchronized="true"
security="false" dataRef="false" />

@ -33,6 +33,9 @@ int main(int argc, char** argv) {
char* hostname;
int tcpPort = 102;
const char* localIp = NULL;
int localTcpPort = -1;
if (argc > 1)
hostname = argv[1];
@ -42,19 +45,34 @@ int main(int argc, char** argv) {
if (argc > 2)
tcpPort = atoi(argv[2]);
if (argc > 3)
localIp = argv[3];
if (argc > 4)
localTcpPort = atoi(argv[4]);
IedClientError error;
IedConnection con = IedConnection_create();
/* Optional bind to local IP address/interface */
if (localIp) {
IedConnection_setLocalAddress(con, localIp, localTcpPort);
printf("Bound to Local Address: %s:%i\n", localIp, localTcpPort);
}
IedConnection_connect(con, &error, hostname, tcpPort);
printf("Connecting to %s:%i\n", hostname, tcpPort);
if (error == IED_ERROR_OK) {
if (error == IED_ERROR_OK)
{
printf("Connected\n");
/* read an analog measurement value from server */
MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX);
if (value != NULL) {
if (value != NULL)
{
if (MmsValue_getType(value) == MMS_FLOAT) {
float fval = MmsValue_toFloat(value);
printf("read float value: %f\n", fval);
@ -134,10 +152,10 @@ close_connection:
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
Thread_sleep(60000);
}
IedConnection_destroy(con);
return 0;
}

@ -0,0 +1,17 @@
set(iec61850_client_example_ClientGooseControl_SRCS
client_example_ClientGooseControl.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_ClientGooseControl_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_ClientGooseControl
${iec61850_client_example_ClientGooseControl_SRCS}
)
target_link_libraries(iec61850_client_example_ClientGooseControl
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_ClientGooseControl
PROJECT_SOURCES = client_example_ClientGooseControl.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,83 @@
/*
* client_example_ClientGooseControl.c
*
* This example is intended to be used with server_example_basic_io or server_example_goose.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
int main(int argc, char** argv)
{
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK)
{
/*Read GoCB Values*/
ClientGooseControlBlock goCB = IedConnection_getGoCBValues(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL);
bool GoEna = ClientGooseControlBlock_getGoEna(goCB);
printf("GoEna Value: %d\n", GoEna);
const char* id = ClientGooseControlBlock_getGoID(goCB);
printf("GoID Value: %s\n", id);
const char* datset = ClientGooseControlBlock_getDatSet(goCB);
printf("GoDatset Value: %s\n", datset);
/*Update Go CB Values locally*/
ClientGooseControlBlock_setGoID(goCB, "analog");
ClientGooseControlBlock_setDatSet(goCB, "simpleIOGenericIO/LLN0$AnalogValues");
ClientGooseControlBlock_setGoEna(goCB, false);
/*Update Go CB Values to server (Throws error because only GoEna is writeable)*/
IedConnection_setGoCBValues(con, &error, goCB, GOCB_ELEMENT_GO_ID | GOCB_ELEMENT_DATSET | GOCB_ELEMENT_GO_ENA, true);
if (error != IED_ERROR_OK)
printf("Fail to Set Values to Server (code: %i)\n", error);
/*Test to see if the values were updated correctly on the server*/
goCB = IedConnection_getGoCBValues(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL);
bool GoEnaUpdate = ClientGooseControlBlock_getGoEna(goCB);
printf("GoEna Value: %d\n", GoEnaUpdate);
const char* idUpdate = ClientGooseControlBlock_getGoID(goCB);
printf("GoID Value: %s\n", idUpdate);
const char* datsetUpdate = ClientGooseControlBlock_getDatSet(goCB);
printf("GoDatset Value: %s\n", datsetUpdate);
printf("\n");
Thread_sleep(50000);
close_connection:
IedConnection_close(con);
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -0,0 +1,17 @@
set(iec61850_client_example_ClientGooseControlAsync_SRCS
client_example_ClientGooseControlAsync.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_ClientGooseControlAsync_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_ClientGooseControlAsync
${iec61850_client_example_ClientGooseControlAsync_SRCS}
)
target_link_libraries(iec61850_client_example_ClientGooseControlAsync
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_ClientGooseControlAsync
PROJECT_SOURCES = client_example_ClientGooseControlAsync.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,142 @@
/*
* client_example_ClientGooseControlAsync.c
*
* This example is intended to be used with server_example_goose.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static ClientGooseControlBlock GOCB = NULL;
static void
getGoCBValuesHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientGooseControlBlock goCB)
{
if (err == IED_ERROR_OK)
{
if (goCB)
{
printf("Access to GoCB\n");
bool GoEna = ClientGooseControlBlock_getGoEna(goCB);
printf("GoEna Value : % d\n", GoEna);
const char* id = ClientGooseControlBlock_getGoID(goCB);
printf("GoID Value: %s\n", id);
const char* datset = ClientGooseControlBlock_getDatSet(goCB);
printf("GoDatset Value: %s\n", datset);
GOCB = goCB;
}
}
else {
printf("Failed to get GoCV values (err=%i)\n", err);
}
}
static void
genericServiceHandler(uint32_t invokeId, void* parameter, IedClientError err)
{
if (err == IED_ERROR_OK) {
printf("Set GoCB Values successful");
}
else {
printf("Error triggering a report (code: %i)\n", err);
}
}
int
main(int argc, char** argv)
{
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK)
{
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED)
{
if (IedConnection_getState(con) == IED_STATE_CLOSED)
{
success = false;
break;
}
Thread_sleep(10);
}
if (success)
{
/*Read GoCB Values*/
IedConnection_getGoCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL, getGoCBValuesHandler, NULL);
if (error != IED_ERROR_OK) {
printf("getGoCBValues service error! %i\n", error);
}
while (GOCB == NULL) {}
if (GOCB != NULL)
{
/*Update Go CB Values locally*/
ClientGooseControlBlock_setGoID(GOCB, "analog");
ClientGooseControlBlock_setDatSet(GOCB, "simpleIOGenericIO/LLN0$AnalogValues");
ClientGooseControlBlock_setGoEna(GOCB, false);
/*Update Go CB Values to server (Throws error because only GoEna is writeable)*/
IedConnection_setGoCBValuesAsync(con, &error, GOCB, GOCB_ELEMENT_GO_ID | GOCB_ELEMENT_DATSET | GOCB_ELEMENT_GO_ENA, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK) {
printf("setGoCBValues service error: %i\n", error);
}
/*Test to see if the values were updated correctly on the server*/
IedConnection_getGoCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.gcbEvents", NULL, getGoCBValuesHandler, NULL);
ClientGooseControlBlock_destroy(GOCB);
}
}
Thread_sleep(10000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK)
{
printf("Release returned error: %d\n", error);
}
else
{
while (IedConnection_getState(con) != IED_STATE_CLOSED)
{
Thread_sleep(10);
}
}
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -28,12 +28,14 @@ printValue(char* name, MmsValue* value)
static void
readObjectHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value)
{
if (err == IED_ERROR_OK) {
if (err == IED_ERROR_OK)
{
printValue((char*) parameter, value);
MmsValue_delete(value);
}
else {
else
{
printf("Failed to read object %s (err=%i)\n", (char*) parameter, err);
}
}
@ -41,22 +43,26 @@ readObjectHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsVa
static void
readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet)
{
if (err == IED_ERROR_OK) {
if (err == IED_ERROR_OK)
{
clientDataSet = dataSet;
printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet));
MmsValue* values = ClientDataSet_getValues(dataSet);
if (MmsValue_getType(values) == MMS_ARRAY) {
if (MmsValue_getType(values) == MMS_ARRAY)
{
int i;
for (i = 0; i < MmsValue_getArraySize(values); i++) {
for (i = 0; i < MmsValue_getArraySize(values); i++)
{
printf(" [%i]", i);
printValue("", MmsValue_getElement(values, i));
}
}
}
else {
else
{
printf("Failed to read data set (err=%i)\n", err);
}
}
@ -64,15 +70,16 @@ readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, Clien
static void
writeDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList /* <MmsValue*> */accessResults)
{
if (err == IED_ERROR_OK) {
if (accessResults) {
if (err == IED_ERROR_OK)
{
if (accessResults)
{
int i = 0;
LinkedList element = LinkedList_getNext(accessResults);
while (element) {
while (element)
{
MmsValue* accessResultValue = (MmsValue*) LinkedList_getData(element);
printf(" access-result[%i]", i);
@ -84,10 +91,10 @@ writeDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, Link
}
LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete);
}
}
else {
else
{
printf("Failed to write data set (err=%i)\n", err);
}
}
@ -100,10 +107,12 @@ reportCallbackFunction(void* parameter, ClientReport report)
printf("received report for %s\n", ClientReport_getRcbReference(report));
int i;
for (i = 0; i < 4; i++) {
for (i = 0; i < 4; i++)
{
ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
if (reason != IEC61850_REASON_NOT_INCLUDED) {
if (reason != IEC61850_REASON_NOT_INCLUDED)
{
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
}
@ -113,12 +122,14 @@ reportCallbackFunction(void* parameter, ClientReport report)
static void
getVarSpecHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsVariableSpecification* spec)
{
if (err == IED_ERROR_OK) {
if (err == IED_ERROR_OK)
{
printf("variable: %s has type %d\n", (char*) parameter, MmsVariableSpecification_getType(spec));
MmsVariableSpecification_destroy(spec);
}
else {
else
{
printf("Failed to get variable specification for object %s (err=%i)\n", (char*) parameter, err);
}
}
@ -126,17 +137,18 @@ getVarSpecHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsVa
static void
getNameListHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList nameList, bool moreFollows)
{
if (err != IED_ERROR_OK) {
if (err != IED_ERROR_OK)
{
printf("Get name list error: %d\n", err);
}
else {
else
{
char* ldName = (char*) parameter;
LinkedList element = LinkedList_getNext(nameList);
while (element) {
while (element)
{
char* variableName = (char*) LinkedList_getData(element);
printf(" %s/%s\n", ldName, variableName);
@ -155,15 +167,17 @@ getServerDirectoryHandler(uint32_t invokeId, void* parameter, IedClientError err
{
IedConnection con = (IedConnection) parameter;
if (err != IED_ERROR_OK) {
if (err != IED_ERROR_OK)
{
printf("Get server directory error: %d\n", err);
}
else {
else
{
LinkedList element = LinkedList_getNext(nameList);
/* Call logical device variables for each logical node */
while (element) {
while (element)
{
char* ldName = (char*) LinkedList_getData(element);
IedClientError cerr;
@ -189,8 +203,8 @@ controlActionHandler(uint32_t invokeId, void* parameter, IedClientError err, Con
printf("control: ID: %d type: %i err: %d success: %i\n", invokeId, type, err, success);
}
int main(int argc, char** argv) {
int main(int argc, char** argv)
{
char* hostname;
int tcpPort = 102;
@ -208,13 +222,14 @@ int main(int argc, char** argv) {
IedConnection_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
if (error == IED_ERROR_OK)
{
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED) {
if (IedConnection_getState(con) == IED_STATE_CLOSED) {
while (IedConnection_getState(con) != IED_STATE_CONNECTED)
{
if (IedConnection_getState(con) == IED_STATE_CLOSED)
{
success = false;
break;
}
@ -222,38 +237,42 @@ int main(int argc, char** argv) {
Thread_sleep(10);
}
if (success) {
if (success)
{
IedConnection_getServerDirectoryAsync(con, &error, NULL, NULL, getServerDirectoryHandler, con);
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("read server directory error %i\n", error);
}
Thread_sleep(1000);
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn1.mag.f");
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("read object error %i\n", error);
}
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn2.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn2.mag.f");
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("read object error %i\n", error);
}
IedConnection_getVariableSpecificationAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1", IEC61850_FC_MX, getVarSpecHandler, "simpleIOGenericIO/GGIO1.AnIn1");
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("get variable specification error %i\n", error);
}
IedConnection_readDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", NULL, readDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("read data set error %i\n", error);
}
@ -265,7 +284,8 @@ int main(int argc, char** argv) {
IedConnection_writeDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", values, writeDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("write data set error %i\n", error);
}
@ -275,40 +295,44 @@ int main(int argc, char** argv) {
ControlObjectClient controlClient = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO1", con);
if (controlClient != NULL) {
if (controlClient != NULL)
{
ControlObjectClient_setOrigin(controlClient, "test1", CONTROL_ORCAT_AUTOMATIC_REMOTE);
MmsValue* ctlVal = MmsValue_newBoolean(true);
ControlObjectClient_operateAsync(controlClient, &error, ctlVal, 0, controlActionHandler, NULL);
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("Failed to send operate %i\n", error);
}
}
else {
else
{
printf("Failed to connect to control object\n");
}
}
Thread_sleep(1000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("Release returned error: %d\n", error);
}
else {
while (IedConnection_getState(con) != IED_STATE_CLOSED) {
else
{
while (IedConnection_getState(con) != IED_STATE_CLOSED)
{
Thread_sleep(10);
}
}
}
else {
else
{
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
@ -318,5 +342,3 @@ int main(int argc, char** argv) {
IedConnection_destroy(con);
return 0;
}

@ -45,8 +45,10 @@ int main(int argc, char** argv) {
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
if (error == IED_ERROR_OK)
{
MmsValue* ctlVal = NULL;
MmsValue* stVal = NULL;
/************************
* Direct control
@ -55,99 +57,116 @@ int main(int argc, char** argv) {
ControlObjectClient control
= ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO1", con);
MmsValue* ctlVal = MmsValue_newBoolean(true);
if (control)
{
ctlVal = MmsValue_newBoolean(true);
ControlObjectClient_setOrigin(control, NULL, 3);
ControlObjectClient_setOrigin(control, NULL, 3);
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO1 operated successfully\n");
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO1\n");
}
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO1 operated successfully\n");
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO1\n");
}
MmsValue_delete(ctlVal);
MmsValue_delete(ctlVal);
ControlObjectClient_destroy(control);
ControlObjectClient_destroy(control);
/* Check if status value has changed */
/* Check if status value has changed */
stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO1.stVal", IEC61850_FC_ST);
MmsValue* stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO1.stVal", IEC61850_FC_ST);
if (error == IED_ERROR_OK) {
bool state = MmsValue_getBoolean(stVal);
MmsValue_delete(stVal);
if (error == IED_ERROR_OK) {
bool state = MmsValue_getBoolean(stVal);
MmsValue_delete(stVal);
printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state);
}
else {
printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO1 failed!\n");
}
printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state);
}
else {
printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO1 failed!\n");
printf("Control object simpleIOGenericIO/GGIO1.SPCSO1 not found in server\n");
}
/************************
* Select before operate
***********************/
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO2", con);
if (ControlObjectClient_select(control)) {
if (control)
{
if (ControlObjectClient_select(control)) {
ctlVal = MmsValue_newBoolean(true);
ctlVal = MmsValue_newBoolean(true);
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO2 operated successfully\n");
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO2 operated successfully\n");
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO2!\n");
}
MmsValue_delete(ctlVal);
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO2!\n");
printf("failed to select simpleIOGenericIO/GGIO1.SPCSO2!\n");
}
MmsValue_delete(ctlVal);
ControlObjectClient_destroy(control);
}
else {
printf("failed to select simpleIOGenericIO/GGIO1.SPCSO2!\n");
printf("Control object simpleIOGenericIO/GGIO1.SPCSO2 not found in server\n");
}
ControlObjectClient_destroy(control);
/****************************************
* Direct control with enhanced security
****************************************/
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO3", con);
ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
if (control)
{
ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
ctlVal = MmsValue_newBoolean(true);
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");
}
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);
MmsValue_delete(ctlVal);
/* Wait for command termination message */
Thread_sleep(1000);
/* Wait for command termination message */
Thread_sleep(1000);
ControlObjectClient_destroy(control);
ControlObjectClient_destroy(control);
/* Check if status value has changed */
/* Check if status value has changed */
stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", IEC61850_FC_ST);
stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", IEC61850_FC_ST);
if (error == IED_ERROR_OK) {
bool state = MmsValue_getBoolean(stVal);
if (error == IED_ERROR_OK) {
bool state = MmsValue_getBoolean(stVal);
printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state);
printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state);
MmsValue_delete(stVal);
MmsValue_delete(stVal);
}
else {
printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n");
}
}
else {
printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n");
printf("Control object simpleIOGenericIO/GGIO1.SPCSO3 not found in server\n");
}
/***********************************************
@ -156,56 +175,66 @@ int main(int argc, char** argv) {
control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO4", con);
ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
if (control)
{
ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
ctlVal = MmsValue_newBoolean(true);
ctlVal = MmsValue_newBoolean(true);
if (ControlObjectClient_selectWithValue(control, ctlVal)) {
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");
}
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO4 operated successfully\n");
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO4!\n");
printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n");
}
MmsValue_delete(ctlVal);
/* Wait for command termination message */
Thread_sleep(1000);
ControlObjectClient_destroy(control);
}
else {
printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n");
printf("Control object simpleIOGenericIO/GGIO1.SPCSO4 not found in server\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 (control)
{
ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n");
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n");
}
ctlVal = MmsValue_newBoolean(true);
MmsValue_delete(ctlVal);
if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n");
}
else {
printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n");
}
/* Wait for command termination message */
Thread_sleep(1000);
MmsValue_delete(ctlVal);
ControlObjectClient_destroy(control);
/* Wait for command termination message */
Thread_sleep(1000);
ControlObjectClient_destroy(control);
}
else {
printf("Control object simpleIOGenericIO/GGIO1.SPCSO9 not found in server\n");
}
IedConnection_close(con);
}

@ -12,10 +12,10 @@
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <Windows.h>
#include <windows.h>
#else
#include <libgen.h>
#endif
@ -31,14 +31,16 @@ dirname(char* path)
int len = strlen(path);
int i = 0;
while (i < len) {
while (i < len)
{
if (path[i] == '/' || path[i] == ':' || path[i] == '\\')
lastSep = path + i;
i++;
}
if (lastSep) {
if (lastSep)
{
strcpy(_dirname, path);
_dirname[lastSep - path] = 0;
}
@ -48,7 +50,6 @@ dirname(char* path)
return _dirname;
}
static char _basename[1000];
static char*
@ -59,7 +60,8 @@ basename(char* path)
int len = strlen(path);
int i = 0;
while (i < len) {
while (i < len)
{
if (path[i] == '/' || path[i] == ':' || path[i] == '\\')
lastSep = path + i;
@ -81,7 +83,8 @@ static int tcpPort = 102;
static char* filename = NULL;
static bool singleRequest = false;
typedef enum {
typedef enum
{
FileOperationType_None = 0,
FileOperationType_Dir,
FileOperationType_Info,
@ -92,17 +95,17 @@ typedef enum {
static FileOperationType operation = FileOperationType_None;
static bool
downloadHandler(void* parameter, uint8_t* buffer, uint32_t bytesRead)
{
FILE* fp = (FILE*) parameter;
FILE* fp = (FILE*)parameter;
printf("received %i bytes\n", bytesRead);
if (bytesRead > 0) {
if (fwrite(buffer, bytesRead, 1, fp) != 1) {
if (bytesRead > 0)
{
if (fwrite(buffer, bytesRead, 1, fp) != 1)
{
printf("Failed to write local file!\n");
return false;
}
@ -128,7 +131,6 @@ printHelp()
printf(" set <filename> - set file\n");
}
static int
parseOptions(int argc, char** argv)
{
@ -136,40 +138,51 @@ parseOptions(int argc, char** argv)
int retVal = 0;
while (currentArgc < argc) {
if (strcmp(argv[currentArgc], "-h") == 0) {
while (currentArgc < argc)
{
if (strcmp(argv[currentArgc], "-h") == 0)
{
hostname = argv[++currentArgc];
}
else if (strcmp(argv[currentArgc], "-p") == 0) {
else if (strcmp(argv[currentArgc], "-p") == 0)
{
tcpPort = atoi(argv[++currentArgc]);
}
else if (strcmp(argv[currentArgc], "-s") == 0) {
else if (strcmp(argv[currentArgc], "-s") == 0)
{
singleRequest = true;
}
else if (strcmp(argv[currentArgc], "del") == 0) {
else if (strcmp(argv[currentArgc], "del") == 0)
{
operation = FileOperationType_Del;
filename = argv[++currentArgc];
}
else if (strcmp(argv[currentArgc], "dir") == 0) {
else if (strcmp(argv[currentArgc], "dir") == 0)
{
operation = FileOperationType_Dir;
}
else if (strcmp(argv[currentArgc], "subdir") == 0) {
else if (strcmp(argv[currentArgc], "subdir") == 0)
{
operation = FileOperationType_Dir;
filename = argv[++currentArgc];
}
else if (strcmp(argv[currentArgc], "info") == 0) {
else if (strcmp(argv[currentArgc], "info") == 0)
{
operation = FileOperationType_Info;
filename = argv[++currentArgc];
}
else if (strcmp(argv[currentArgc], "get") == 0) {
else if (strcmp(argv[currentArgc], "get") == 0)
{
operation = FileOperationType_Get;
filename = argv[++currentArgc];
}
else if (strcmp(argv[currentArgc], "set") == 0) {
else if (strcmp(argv[currentArgc], "set") == 0)
{
operation = FileOperationType_Set;
filename = argv[++currentArgc];
}
else {
else
{
printf("Unknown operation!\n");
return 1;
}
@ -195,22 +208,25 @@ showDirectory(IedConnection con)
else
rootDirectory = IedConnection_getFileDirectory(con, &error, filename);
if (error != IED_ERROR_OK) {
if (error != IED_ERROR_OK)
{
printf("Error retrieving file directory\n");
}
else {
else
{
LinkedList directoryEntry = LinkedList_getNext(rootDirectory);
while (directoryEntry != NULL) {
while (directoryEntry != NULL)
{
FileDirectoryEntry entry = (FileDirectoryEntry) directoryEntry->data;
FileDirectoryEntry entry = (FileDirectoryEntry)directoryEntry->data;
printf("%s %i\n", FileDirectoryEntry_getFileName(entry), FileDirectoryEntry_getFileSize(entry));
directoryEntry = LinkedList_getNext(directoryEntry);
}
LinkedList_destroyDeep(rootDirectory, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy);
LinkedList_destroyDeep(rootDirectory, (LinkedListValueDeleteFunction)FileDirectoryEntry_destroy);
}
if (moreFollows)
@ -228,10 +244,11 @@ getFile(IedConnection con)
FILE* fp = fopen(localFilename, "wb");
if (fp != NULL) {
if (fp != NULL)
{
/* Download a file from the server */
IedConnection_getFile(con, &error, filename, downloadHandler, (void*) fp);
IedConnection_getFile(con, &error, filename, downloadHandler, (void*)fp);
if (error != IED_ERROR_OK)
printf("Failed to get file!\n");
@ -290,14 +307,16 @@ deleteFile(IedConnection con)
int
main(int argc, char** argv)
{
if (argc < 2) {
if (argc < 2)
{
printHelp();
return 0;
}
parseOptions(argc, argv);
if (operation == FileOperationType_None) {
if (operation == FileOperationType_None)
{
printHelp();
return 0;
}
@ -308,10 +327,10 @@ main(int argc, char** argv)
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
switch (operation) {
if (error == IED_ERROR_OK)
{
switch (operation)
{
case FileOperationType_Dir:
showDirectory(con);
break;
@ -330,15 +349,13 @@ main(int argc, char** argv)
break;
}
IedConnection_abort(con, &error);
}
else {
else
{
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -5,13 +5,12 @@
*/
#include "iec61850_client.h"
#include "hal_thread.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
//#include "hal_thread.h"
static void
printJournalEntries(LinkedList journalEntries)
{
@ -19,8 +18,8 @@ printJournalEntries(LinkedList journalEntries)
LinkedList journalEntriesElem = LinkedList_getNext(journalEntries);
while (journalEntriesElem != NULL) {
while (journalEntriesElem != NULL)
{
MmsJournalEntry journalEntry = (MmsJournalEntry) LinkedList_getData(journalEntriesElem);
MmsValue_printToBuffer(MmsJournalEntry_getEntryID(journalEntry), buf, 1024);
@ -30,8 +29,8 @@ printJournalEntries(LinkedList journalEntries)
LinkedList journalVariableElem = LinkedList_getNext(journalEntry->journalVariables);
while (journalVariableElem != NULL) {
while (journalVariableElem != NULL)
{
MmsJournalVariable journalVariable = (MmsJournalVariable) LinkedList_getData(journalVariableElem);
printf(" variable-tag: %s\n", MmsJournalVariable_getTag(journalVariable));
@ -45,8 +44,9 @@ printJournalEntries(LinkedList journalEntries)
}
}
int main(int argc, char** argv) {
int
main(int argc, char** argv)
{
char* hostname;
int tcpPort = 102;
@ -58,7 +58,7 @@ int main(int argc, char** argv) {
if (argc > 2)
tcpPort = atoi(argv[2]);
char* logRef = "simpleIOGenericIO/LLN0$EventLog";
char* logRef = "TestIEDGenericIO/LLN0$EventLog";
IedClientError error;
@ -66,19 +66,21 @@ int main(int argc, char** argv) {
IedConnection_connect(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
if (error == IED_ERROR_OK)
{
/* read list of logs in LN (optional - if you don't know the existing logs) */
LinkedList logs = IedConnection_getLogicalNodeDirectory(con, &error, "simpleIOGenericIO/LLN0", ACSI_CLASS_LOG);
if (error == IED_ERROR_OK) {
LinkedList logs = IedConnection_getLogicalNodeDirectory(con, &error, "TestIEDGenericIO/LLN0", ACSI_CLASS_LOG);
if (LinkedList_size(logs) > 0) {
if (error == IED_ERROR_OK)
{
if (LinkedList_size(logs) > 0)
{
printf("Found logs in LN simpleIOGenericIO/LLN0:\n");
LinkedList log = LinkedList_getNext(logs);
while (log != NULL) {
while (log != NULL)
{
char* logName = (char*) LinkedList_getData(log);
printf(" %s\n", logName);
@ -86,18 +88,31 @@ int main(int argc, char** argv) {
log = LinkedList_getNext(log);
}
}
else {
else
{
printf("No logs found\n");
}
LinkedList_destroy(logs);
}
/* read log control block (using the generic read function) */
MmsValue* lcbValue = IedConnection_readObject(con, &error, "simpleIOGenericIO/LLN0.EventLog", IEC61850_FC_LG);
IedConnection_writeBooleanValue(con, &error, "TestIEDGenericIO/LLN0.EventLog.LogEna", IEC61850_FC_LG, true);
if (error == IED_ERROR_OK)
{
printf("Enabled log. Waiting ...\n");
Thread_sleep(1000);
}
else
{
printf("Failed to enable log (err=%i)\n", error);
}
if ((error == IED_ERROR_OK) && (MmsValue_getType(lcbValue) != MMS_DATA_ACCESS_ERROR)) {
/* read log control block (using the generic read function) */
MmsValue* lcbValue = IedConnection_readObject(con, &error, "TestIEDGenericIO/LLN0.EventLog", IEC61850_FC_LG);
if ((error == IED_ERROR_OK) && (MmsValue_getType(lcbValue) != MMS_DATA_ACCESS_ERROR))
{
char printBuf[1024];
MmsValue_printToBuffer(lcbValue, printBuf, 1024);
@ -115,9 +130,12 @@ int main(int argc, char** argv) {
* read the log contents. Be aware that the logRef uses the '$' sign as separator between the LN and
* the log name! This is in contrast to the LCB object reference above.
*/
LinkedList logEntries = IedConnection_queryLogAfter(con, &error, "simpleIOGenericIO/LLN0$EventLog", oldEntry, timestamp, &moreFollows);
LinkedList logEntries = IedConnection_queryLogAfter(con, &error, logRef, oldEntry, timestamp, &moreFollows);
if (error == IED_ERROR_OK)
{
printf("Received %d log entries for %s\n", LinkedList_size(logEntries), logRef);
if (error == IED_ERROR_OK) {
printJournalEntries(logEntries);
LinkedList_destroyDeep(logEntries, (LinkedListValueDeleteFunction) MmsJournalEntry_destroy);
@ -132,15 +150,14 @@ int main(int argc, char** argv) {
else
printf("Read LCB failed!\n");
IedConnection_abort(con, &error);
}
else {
else
{
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -0,0 +1,17 @@
set(iec61850_client_example_rcbAsync_SRCS
client_example_rcbAsync.c
)
IF(MSVC)
set_source_files_properties(${iec61850_client_example_rcbAsync_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(iec61850_client_example_rcbAsync
${iec61850_client_example_rcbAsync_SRCS}
)
target_link_libraries(iec61850_client_example_rcbAsync
iec61850
)

@ -0,0 +1,17 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = client_example_rcbAsync
PROJECT_SOURCES = client_example_rcbAsync.c
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,226 @@
/*
* client_example_rcbAsync.c
*
* This example is intended to be used with server_example_basic_io or server_example_goose.
*/
#include "iec61850_client.h"
#include <stdlib.h>
#include <stdio.h>
#include "hal_thread.h"
static ClientDataSet clientDataSet = NULL;
static ClientReportControlBlock RCB = NULL;
static void
printValue(char* name, MmsValue* value)
{
char buf[1000];
MmsValue_printToBuffer(value, buf, 1000);
printf("%s: %s\n", name, buf);
}
static void
readObjectHandler(uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value)
{
if (err == IED_ERROR_OK) {
printValue((char*)parameter, value);
MmsValue_delete(value);
}
else {
printf("Failed to read object %s (err=%i)\n", (char*)parameter, err);
}
}
static void
readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet)
{
if (err == IED_ERROR_OK) {
clientDataSet = dataSet;
printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet));
MmsValue* values = ClientDataSet_getValues(dataSet);
if (MmsValue_getType(values) == MMS_ARRAY) {
int i;
for (i = 0; i < MmsValue_getArraySize(values); i++) {
printf(" [%i]", i);
printValue("", MmsValue_getElement(values, i));
}
}
}
else {
printf("Failed to read data set (err=%i\n", err);
}
}
void
reportCallbackFunction(void* parameter, ClientReport report)
{
MmsValue* dataSetValues = ClientReport_getDataSetValues(report);
printf("received report for %s\n", ClientReport_getRcbReference(report));
int i;
for (i = 0; i < 4; i++) {
ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
if (reason != IEC61850_REASON_NOT_INCLUDED) {
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
}
}
}
static void
getRCBValuesHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientReportControlBlock rcb)
{
if (err == IED_ERROR_OK) {
if (rcb) {
bool rptEna = ClientReportControlBlock_getRptEna(rcb);
printf("RptEna = %i\n", rptEna);
const char* RptId = ClientReportControlBlock_getRptId(rcb);
printf("RptID = %s\n", RptId);
RCB = rcb;
}
}
else{
printf("Failed to get RCB Values (err=%i)\n", err);
}
};
static void
genericServiceHandler(uint32_t invokeId, void* parameter, IedClientError err)
{
if (err == IED_ERROR_OK) {
printf("Success triggering a GI report\n");
}
else {
printf("Error triggering a GI report (code: %i)\n", err);
}
}
int main(int argc, char** argv) {
char* hostname;
int tcpPort = 102;
if (argc > 1)
hostname = argv[1];
else
hostname = "localhost";
if (argc > 2)
tcpPort = atoi(argv[2]);
IedClientError error;
IedConnection con = IedConnection_create();
IedConnection_connectAsync(con, &error, hostname, tcpPort);
if (error == IED_ERROR_OK) {
bool success = true;
while (IedConnection_getState(con) != IED_STATE_CONNECTED) {
if (IedConnection_getState(con) == IED_STATE_CLOSED) {
success = false;
break;
}
Thread_sleep(10);
}
if (success) {
/*read measurement value from server*/
IedConnection_readObjectAsync(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX, readObjectHandler, "simpleIOGenericIO/GGIO1.AnIn2.mag.f");
if (error != IED_ERROR_OK) {
printf("read object error %i\n", error);
}
/*read data set*/
IedConnection_readDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", NULL, readDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("read data set error %i\n", error);
}
/* Read RCB values from server*/
IedConnection_getRCBValuesAsync(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL, getRCBValuesHandler, NULL);
if (error != IED_ERROR_OK) {
printf("getRCBValues service error! %i\n", error);
}
while (RCB == NULL) {}
if (RCB != NULL) {
/*Set RCB Values locally*/
ClientReportControlBlock_setResv(RCB, true);
ClientReportControlBlock_setTrgOps(RCB, TRG_OPT_DATA_CHANGED | TRG_OPT_QUALITY_CHANGED | TRG_OPT_GI);
ClientReportControlBlock_setDataSetReference(RCB, "simpleIOGenericIO/LLN0$Events"); /* NOTE the "$" instead of "." ! */
ClientReportControlBlock_setRptEna(RCB, true);
ClientReportControlBlock_setGI(RCB, true);
/*Set RCB Values to server*/
IedConnection_setRCBValuesAsync(con, &error, RCB, RCB_ELEMENT_RESV | RCB_ELEMENT_DATSET | RCB_ELEMENT_TRG_OPS | RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_GI, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK) {
printf("setRCBValues service error!\n");
}
Thread_sleep(1000);
/*Trigger GI Report*/
ClientReportControlBlock_setGI(RCB, true);
IedConnection_setRCBValuesAsync(con, &error, RCB, RCB_ELEMENT_GI, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK)
printf("Error triggering a GI report (code: %i)\n", error);
Thread_sleep(60000);
/*Disable Reporting*/
ClientReportControlBlock_setRptEna(RCB, false);
IedConnection_setRCBValuesAsync(con, &error, RCB, RCB_ELEMENT_RPT_ENA, true, genericServiceHandler, NULL);
if (error != IED_ERROR_OK)
printf("disable reporting failed (code: %i)\n", error);
ClientDataSet_destroy(clientDataSet);
ClientReportControlBlock_destroy(RCB);
}
}
Thread_sleep(50000);
IedConnection_releaseAsync(con, &error);
if (error != IED_ERROR_OK) {
printf("Release returned error: %d\n", error);
}
else {
while (IedConnection_getState(con) != IED_STATE_CLOSED) {
Thread_sleep(10);
}
}
}
else {
printf("Failed to connect to %s:%i\n", hostname, tcpPort);
}
IedConnection_destroy(con);
return 0;
}

@ -101,6 +101,7 @@ printRawMmsMessage(void* parameter, uint8_t* message, int messageLength, bool re
int main(int argc, char** argv)
{
int returnCode = 0;
char* hostname = StringUtils_copyString("localhost");
int tcpPort = 102;
@ -128,7 +129,8 @@ int main(int argc, char** argv)
int c;
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1) {
while ((c = getopt(argc, argv, "mifdh:p:l:t:a:r:g:j:x:v:c:y:z:")) != -1)
{
switch (c) {
case 'm':
printRawMmsMessages = 1;
@ -211,18 +213,28 @@ int main(int argc, char** argv)
if (printRawMmsMessages)
MmsConnection_setRawMessageHandler(con, (MmsRawMessageHandler) printRawMmsMessage, NULL);
if (!MmsConnection_connect(con, &error, hostname, tcpPort)) {
if (!MmsConnection_connect(con, &error, hostname, tcpPort))
{
printf("MMS connect failed!\n");
if (error != MMS_ERROR_NONE)
returnCode = error;
goto exit;
}
else
printf("MMS connected.\n");
if (identifyDevice) {
if (identifyDevice)
{
MmsServerIdentity* identity =
MmsConnection_identify(con, &error);
if (identity != NULL) {
if (error != MMS_ERROR_NONE)
returnCode = error;
if (identity != NULL)
{
printf("\nServer identity:\n----------------\n");
printf(" vendor:\t%s\n", identity->vendorName);
printf(" model:\t%s\n", identity->modelName);
@ -232,23 +244,37 @@ int main(int argc, char** argv)
printf("Reading server identity failed!\n");
}
if (readDeviceList) {
if (readDeviceList)
{
printf("\nDomains present on server:\n--------------------------\n");
LinkedList nameList = MmsConnection_getDomainNames(con, &error);
LinkedList_printStringList(nameList);
LinkedList_destroy(nameList);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (nameList)
{
LinkedList_printStringList(nameList);
LinkedList_destroy(nameList);
}
}
if (getDeviceDirectory) {
if (getDeviceDirectory)
{
LinkedList variableList = MmsConnection_getDomainVariableNames(con, &error,
domainName);
if (variableList) {
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList)
{
LinkedList element = LinkedList_getNext(variableList);
printf("\nMMS domain variables for domain %s\n", domainName);
while (element != NULL) {
while (element != NULL)
{
char* name = (char*) element->data;
printf(" %s\n", name);
@ -264,8 +290,11 @@ int main(int argc, char** argv)
variableList = MmsConnection_getDomainJournals(con, &error, domainName);
if (variableList) {
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList)
{
LinkedList element = variableList;
printf("\nMMS journals for domain %s\n", domainName);
@ -281,18 +310,17 @@ int main(int argc, char** argv)
else {
printf("\nFailed to read domain journals (error=%d)\n", error);
}
}
if (readJournal) {
if (readJournal)
{
printf(" read journal %s...\n", journalName);
char* logDomain = journalName;
char* logName = strchr(journalName, '/');
if (logName != NULL) {
if (logName != NULL)
{
logName[0] = 0;
logName++;
@ -309,14 +337,18 @@ int main(int argc, char** argv)
LinkedList journalEntries = MmsConnection_readJournalTimeRange(con, &error, logDomain, logName, startTime, endTime,
&moreFollows);
if (error != MMS_ERROR_NONE)
returnCode = error;
MmsValue_delete(startTime);
MmsValue_delete(endTime);
if (journalEntries != NULL) {
if (journalEntries != NULL)
{
bool readNext;
do {
do
{
readNext = false;
LinkedList lastEntry = LinkedList_getLastElement(journalEntries);
@ -330,7 +362,8 @@ int main(int argc, char** argv)
LinkedList_destroyDeep(journalEntries, (LinkedListValueDeleteFunction)
MmsJournalEntry_destroy);
if (moreFollows) {
if (moreFollows)
{
char buf[100];
MmsValue_printToBuffer(nextEntryId, buf, 100);
@ -351,12 +384,14 @@ int main(int argc, char** argv)
printf(" Invalid log name!\n");
}
if (readVariable) {
if (readWriteHasDomain) {
if (readVariable)
{
if (readWriteHasDomain)
{
MmsValue* result;
if (componentName == NULL) {
if (componentName == NULL)
{
if (arrayIndex == -1) {
result = MmsConnection_readVariable(con, &error, domainName, variableName);
}
@ -373,13 +408,18 @@ int main(int argc, char** argv)
}
}
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
printf("Read SUCCESS\n");
if (result != NULL) {
if (result != NULL)
{
char outbuf[1024];
MmsValue_printToBuffer(result, outbuf, 1024);
@ -391,20 +431,27 @@ int main(int argc, char** argv)
else
printf("result: NULL\n");
}
}
else
{
printf("Reading VMD scope variable not yet supported!\n");
}
}
if (readVariableList) {
if (readWriteHasDomain) {
if (readVariableList)
{
if (readWriteHasDomain)
{
MmsValue* variables = MmsConnection_readNamedVariableListValues(con, &error, domainName, variableName, true);
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
printf("Read SUCCESS\n");
}
}
@ -412,22 +459,28 @@ int main(int argc, char** argv)
printf("Reading VMD scope variable list not yet supported!\n");
}
if (readDataSetDirectory) {
if (readWriteHasDomain) {
if (readDataSetDirectory)
{
if (readWriteHasDomain)
{
bool deletable = false;
LinkedList varListDir = MmsConnection_readNamedVariableListDirectory(con, &error, domainName, variableName, &deletable);
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Reading variable list directory failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
LinkedList varListElem = LinkedList_getNext(varListDir);
int listIdx = 0;
while (varListElem) {
while (varListElem)
{
MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(varListElem);
if (varAccessSpec->arrayIndex)
@ -447,33 +500,46 @@ int main(int argc, char** argv)
printf("Reading VMD scope variable list not yet supported!\n");
}
if (showFileList) {
if (showFileList)
{
char lastName[300];
lastName[0] = 0;
char* continueAfter = NULL;
while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName)) {
while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName))
{
if (error != MMS_ERROR_NONE)
returnCode = error;
continueAfter = lastName;
}
}
if (getFileAttributes) {
if (getFileAttributes)
{
MmsConnection_getFileDirectory(con, &error, filename, NULL, mmsGetFileAttributeHandler, NULL);
if (error != MMS_ERROR_NONE)
returnCode = error;
}
if (deleteFile) {
if (deleteFile)
{
MmsConnection_fileDelete(con, &error, filename);
if (error != MMS_ERROR_NONE) {
if (error != MMS_ERROR_NONE)
{
printf("Delete file failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
else
{
printf("File deleted\n");
}
}
exit:
exit:
free(hostname);
free(domainName);
free(variableName);
@ -482,6 +548,5 @@ int main(int argc, char** argv)
MmsConnection_destroy(con);
return 0;
return returnCode;
}

@ -41,6 +41,8 @@ main(int argc, char **argv)
signal(SIGINT, sigint_handler);
/* Call RSession_setLocalAddress to use a particular interface to send the R-GOOSE messages */
//RSession_setLocalAddress(rSession, "169.254.110.126", -1);
RSession_setRemoteAddress(rSession, dstAddress, 102);
LinkedList dataSetValues = LinkedList_create();
@ -68,6 +70,8 @@ main(int argc, char **argv)
GoosePublisher_setDataSetRef(publisher, "simpleIOGenericIO/LLN0$AnalogValues");
GoosePublisher_setTimeAllowedToLive(publisher, 500);
RSession_start(rSession);
while (running) {
int i = 0;
@ -103,7 +107,3 @@ main(int argc, char **argv)
return 0;
}

@ -21,10 +21,10 @@ main(int argc, char** argv)
{
RSession rSession = RSession_create();
if (rSession) {
//RSession_setRemoteAddress(sessionP, "192.168.56.101", 102);
//RSession_setRemoteAddress(rSession, "192.168.2.227", 102);
if (rSession)
{
/* Call RSession_setLocalAddress to use a particular interface to send the R-GOOSE messages */
//RSession_setLocalAddress(rSession, "169.254.110.126", -1);
RSession_setRemoteAddress(rSession, "230.0.10.10", 102);
SVPublisher svPublisher = SVPublisher_createRemote(rSession, 0x4000);
@ -32,8 +32,8 @@ main(int argc, char** argv)
uint32_t activeKeyId = 1;
uint64_t nextKeyChangeTime = Hal_getTimeInMs() + 5000;
if (svPublisher) {
if (svPublisher)
{
signal(SIGINT, sigint_handler);
char* key1 = "0123456789ABCDEF";
@ -61,7 +61,10 @@ main(int argc, char** argv)
float fVal1 = 1234.5678f;
float fVal2 = 0.12345f;
while (running) {
RSession_start(rSession);
while (running)
{
Timestamp ts;
Timestamp_clearFlags(&ts);
Timestamp_setTimeInMilliseconds(&ts, Hal_getTimeInMs());
@ -82,7 +85,8 @@ main(int argc, char** argv)
SVPublisher_publish(svPublisher);
if (Hal_getTimeInMs() >= nextKeyChangeTime) {
if (Hal_getTimeInMs() >= nextKeyChangeTime)
{
/* change key */
if (activeKeyId == 1)
@ -99,14 +103,15 @@ main(int argc, char** argv)
SVPublisher_destroy(svPublisher);
}
else {
else
{
printf("Failed to create SV publisher\n");
}
RSession_destroy(rSession);
}
else {
else
{
printf("Failed to create remote session instance\n");
}
}

@ -50,8 +50,8 @@ main(int argc, char** argv)
{
RSession rSession = RSession_create();
if (rSession) {
if (rSession)
{
RSession_setLocalAddress(rSession, "0.0.0.0", 102);
RSession_addMulticastGroup(rSession, "230.0.10.10");
@ -64,7 +64,8 @@ main(int argc, char** argv)
SVReceiver receiver = SVReceiver_createRemote(rSession);
if (receiver) {
if (receiver)
{
/* Create a subscriber listening to SV messages with APPID 4000h */
SVSubscriber subscriber = SVSubscriber_create(NULL, 0x4000);
@ -77,7 +78,8 @@ main(int argc, char** argv)
/* Start listening to SV messages - starts a new receiver background thread */
SVReceiver_start(receiver);
if (SVReceiver_isRunning(receiver)) {
if (SVReceiver_isRunning(receiver))
{
signal(SIGINT, sigint_handler);
while (running)
@ -86,21 +88,23 @@ main(int argc, char** argv)
/* Stop listening to SV messages */
SVReceiver_stop(receiver);
}
else {
else
{
printf("Failed to start SV subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n");
}
/* Cleanup and free resources */
SVReceiver_destroy(receiver);
}
else {
else
{
printf("Failed to create SV receiver\n");
}
RSession_destroy(rSession);
}
else {
else
{
printf("Failed to create remote session protocol\n");
}
}

@ -0,0 +1,21 @@
include_directories(
.
)
set(server_example_SRCS
server_example_access_control.c
static_model.c
)
IF(MSVC)
set_source_files_properties(${server_example_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF(MSVC)
add_executable(server_example_access_control
${server_example_SRCS}
)
target_link_libraries(server_example_access_control
iec61850
)

@ -0,0 +1,32 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = server_example_access_control
PROJECT_SOURCES = server_example_access_control.c
PROJECT_SOURCES += static_model.c
PROJECT_ICD_FILE = simpleIO_direct_control.cid
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
LDLIBS += -lm
CP = cp
model: $(PROJECT_ICD_FILE)
java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE)
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
mkdir -p vmd-filestore
$(CP) $(PROJECT_BINARY_NAME) vmd-filestore/IEDSERVER.BIN
clean:
rm -f $(PROJECT_BINARY_NAME)
rm -f vmd-filestore/IEDSERVER.BIN

@ -0,0 +1,377 @@
/*
* server_example_access_control.c
*
* - How to use access control mechanisms
* - How to implement RBAC features based on access control mechanisms
*/
#include "iec61850_server.h"
#include "hal_thread.h"
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "static_model.h"
static int running = 0;
static IedServer iedServer = NULL;
void
sigint_handler(int signalId)
{
running = 0;
}
static const char*
ACSIClassToStr(ACSIClass acsiClass)
{
switch (acsiClass)
{
case ACSI_CLASS_BRCB:
return "BRCB";
case ACSI_CLASS_URCB:
return "URCB";
case ACSI_CLASS_GoCB:
return "GoCB";
case ACSI_CLASS_SGCB:
return "SGCB";
case ACSI_CLASS_LCB:
return "LCB";
case ACSI_CLASS_GsCB:
return "GsCB";
case ACSI_CLASS_LOG:
return "log";
case ACSI_CLASS_DATA_SET:
return "dataset";
case ACSI_CLASS_DATA_OBJECT:
return "data-object";
case ACSI_CLASS_MSVCB:
return "MSVCB";
case ACSI_CLASS_USVCB:
return "USVCB";
default:
return "unknown";
}
}
static ControlHandlerResult
controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* value, bool test)
{
if (test)
return CONTROL_RESULT_FAILED;
if (MmsValue_getType(value) == MMS_BOOLEAN) {
printf("received binary control command: ");
if (MmsValue_getBoolean(value))
printf("on\n");
else
printf("off\n");
}
else
return CONTROL_RESULT_FAILED;
uint64_t timeStamp = Hal_getTimeInMs();
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value);
}
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value);
}
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value);
}
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value);
}
return CONTROL_RESULT_OK;
}
static void
connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
{
if (connected)
printf("Connection opened\n");
else
printf("Connection closed\n");
}
/*
* This handler is called before the rcbEventHandler and can be use to allow or permit read or write access to the RCB
*/
static bool
controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType)
{
printf("%s %s access %s/%s.%s.%s\n", ACSIClassToStr(acsiClass), accessType == IEC61850_CB_ACCESS_TYPE_WRITE ? "write" : "read", ld->name, ln->name, objectName, subObjectName);
/* allow only read access to LCBs */
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
else
return false;
}
/* allow only read access to BRCBs */
if (acsiClass == ACSI_CLASS_BRCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
else
return false;
}
/* to all other control blocks allow read and write access */
return true;
}
static void
rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
{
if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER)) {
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
printf(" param: %s\n", parameterName);
printf(" result: %i\n", serviceError);
}
if (event == RCB_EVENT_ENABLE) {
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
char* rptId = ReportControlBlock_getRptID(rcb);
printf(" rptID: %s\n", rptId);
char* dataSet = ReportControlBlock_getDataSet(rcb);
printf(" datSet: %s\n", dataSet);
free(rptId);
free(dataSet);
}
}
static bool
dataSetAccessHandler(void* parameter, ClientConnection connection, IedServer_DataSetOperation operation, const char* datasetRef)
{
printf("Data set access: %s operation: %i\n", datasetRef, operation);
return true;
}
static MmsDataAccessError
readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, FunctionalConstraint fc, ClientConnection connection, void* parameter)
{
printf("Read access to %s/%s.%s\n", ld->name, ln->name, dataObject ? dataObject->name : "-");
if (dataObject == NULL) {
if (!strcmp(ln->name, "GGIO1")) {
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
}
else {
if (!strcmp(ln->name, "GGIO1") && !strcmp(dataObject->name, "AnIn1")) {
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
}
return DATA_ACCESS_ERROR_SUCCESS;
}
static bool
listObjectsAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, FunctionalConstraint fc)
{
if (subObjectName)
printf("list objects access[2] to %s/%s.%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, subObjectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc));
else
printf("list objects access[2] to %s/%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc));
// if (acsiClass == ACSI_CLASS_BRCB) {
// return true;
// }
// return false;
return true;
}
static bool
directoryAccessHandler(void* parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice* logicalDevice)
{
switch(category) {
case DIRECTORY_CAT_LD_LIST:
printf("Get list of logical devices from %s\n", ClientConnection_getPeerAddress(connection));
break;
case DIRECTORY_CAT_DATASET_LIST:
printf("Get list of datasets for LD %s from %s\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection));
break;
case DIRECTORY_CAT_DATA_LIST:
printf("Get list of data for LD %s from %s\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection));
break;
case DIRECTORY_CAT_LOG_LIST:
printf("Get list of logs for LD %s from %s -> reject\n", ModelNode_getName((ModelNode*)logicalDevice), ClientConnection_getPeerAddress(connection));
return false;
break;
}
return true;
}
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
/* Create new server configuration object */
IedServerConfig config = IedServerConfig_create();
/* Set buffer size for buffered report control blocks to 200000 bytes */
IedServerConfig_setReportBufferSize(config, 200000);
/* Set stack compliance to a specific edition of the standard (WARNING: data model has also to be checked for compliance) */
IedServerConfig_setEdition(config, IEC_61850_EDITION_2);
/* Set the base path for the MMS file services */
IedServerConfig_setFileServiceBasePath(config, "./vmd-filestore/");
/* disable MMS file service */
IedServerConfig_enableFileService(config, false);
/* enable dynamic data set service */
IedServerConfig_enableDynamicDataSetService(config, true);
/* disable log service */
IedServerConfig_enableLogService(config, false);
/* set maximum number of clients */
IedServerConfig_setMaxMmsConnections(config, 2);
/* Create a new IEC 61850 server instance */
iedServer = IedServer_createWithConfig(&iedModel, NULL, config);
/* configuration object is no longer required */
IedServerConfig_destroy(config);
/* set the identity values for MMS identify service */
IedServer_setServerIdentity(iedServer, "libiec61850.com", "access control example", "1.0.0");
/* Install handler for operate command */
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO2);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO3);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO4);
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
/* Install handler to log RCB events */
IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL);
/* Install handler to control access to control blocks (RCBs, LCBs, GoCBs, SVCBs, SGCBs)*/
IedServer_setControlBlockAccessHandler(iedServer, controlBlockAccessHandler, NULL);
/* By default access to variables with FC=DC and FC=CF is not allowed.
* This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used
* by iec61850_client_example1.
*/
IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW);
/* Install handler to perform access control on datasets */
IedServer_setDataSetAccessHandler(iedServer, dataSetAccessHandler, NULL);
/* Install handler to perform read access control on data model elements
* NOTE: when read access to a data model element is blocked this will also prevent the client
* to read the data model element in a data set or enable a RCB instance that uses a dataset
* containing the restricted data model element.
*/
IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL);
IedServer_setDirectoryAccessHandler(iedServer, directoryAccessHandler, NULL);
/* control visibility of data objects in directory (get-name-list) and variable description (get-variable-access-attributes) services */
IedServer_setListObjectsAccessHandler(iedServer, listObjectsAccessHandler, NULL);
/* MMS server will be instructed to start listening for client connections. */
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed (maybe need root permissions or another server is already using the port)! Exit.\n");
IedServer_destroy(iedServer);
exit(-1);
}
running = 1;
signal(SIGINT, sigint_handler);
float t = 0.f;
while (running) {
uint64_t timestamp = Hal_getTimeInMs();
t += 0.1f;
float an1 = sinf(t);
float an2 = sinf(t + 1.f);
float an3 = sinf(t + 2.f);
float an4 = sinf(t + 3.f);
Timestamp iecTimestamp;
Timestamp_clearFlags(&iecTimestamp);
Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp);
Timestamp_setLeapSecondKnown(&iecTimestamp, true);
/* toggle clock-not-synchronized flag in timestamp */
if (((int) t % 2) == 0)
Timestamp_setClockNotSynchronized(&iecTimestamp, true);
#if 1
IedServer_lockDataModel(iedServer);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4);
IedServer_unlockDataModel(iedServer);
#endif
Thread_sleep(100);
}
/* stop MMS server - close TCP server socket and all client sockets */
IedServer_stop(iedServer);
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
return 0;
} /* main() */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,311 @@
/*
* static_model.h
*
* automatically generated from simpleIO_direct_control.cid
*/
#ifndef STATIC_MODEL_H_
#define STATIC_MODEL_H_
#include <stdlib.h>
#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
extern LogicalNode iedModel_GenericIO_LLN0;
extern DataObject iedModel_GenericIO_LLN0_Mod;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_q;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_t;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel;
extern DataObject iedModel_GenericIO_LLN0_Beh;
extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal;
extern DataAttribute iedModel_GenericIO_LLN0_Beh_q;
extern DataAttribute iedModel_GenericIO_LLN0_Beh_t;
extern DataObject iedModel_GenericIO_LLN0_Health;
extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal;
extern DataAttribute iedModel_GenericIO_LLN0_Health_q;
extern DataAttribute iedModel_GenericIO_LLN0_Health_t;
extern DataObject iedModel_GenericIO_LLN0_NamPlt;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs;
extern LogicalNode iedModel_GenericIO_LPHD1;
extern DataObject iedModel_GenericIO_LPHD1_PhyNam;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor;
extern DataObject iedModel_GenericIO_LPHD1_PhyHealth;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t;
extern DataObject iedModel_GenericIO_LPHD1_Proxy;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t;
extern LogicalNode iedModel_GenericIO_GGIO1;
extern DataObject iedModel_GenericIO_GGIO1_Mod;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel;
extern DataObject iedModel_GenericIO_GGIO1_Beh;
extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t;
extern DataObject iedModel_GenericIO_GGIO1_Health;
extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Health_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Health_t;
extern DataObject iedModel_GenericIO_GGIO1_NamPlt;
extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor;
extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev;
extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d;
extern DataObject iedModel_GenericIO_GGIO1_AnIn1;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t;
extern DataObject iedModel_GenericIO_GGIO1_AnIn2;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t;
extern DataObject iedModel_GenericIO_GGIO1_AnIn3;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t;
extern DataObject iedModel_GenericIO_GGIO1_AnIn4;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO1;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO2;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO3;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO4;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind1;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind2;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind3;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind4;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO (&iedModel_GenericIO)
#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0)
#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod)
#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal)
#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q)
#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t)
#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel)
#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh)
#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal)
#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q)
#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t)
#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health)
#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal)
#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q)
#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t)
#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt)
#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor)
#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev)
#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d)
#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev)
#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs)
#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1)
#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam)
#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t)
#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy)
#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal)
#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q)
#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t)
#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1)
#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod)
#define IEDMODEL_GenericIO_GGIO1_Mod_stVal (&iedModel_GenericIO_GGIO1_Mod_stVal)
#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q)
#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t)
#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh)
#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal)
#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q)
#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t)
#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health)
#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal)
#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q)
#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t)
#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt)
#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor)
#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev)
#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d)
#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t)
#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t)
#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t)
#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin (&iedModel_GenericIO_GGIO1_SPCSO1_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t)
#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)
#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t)
#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2)
#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q)
#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t)
#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3)
#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q)
#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t)
#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4)
#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q)
#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t)
#endif /* STATIC_MODEL_H_ */

@ -66,7 +66,6 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v
return CONTROL_RESULT_OK;
}
static void
connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
{
@ -81,12 +80,14 @@ rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conne
{
printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event);
if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER)) {
if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER))
{
printf(" param: %s\n", parameterName);
printf(" result: %i\n", serviceError);
}
if (event == RCB_EVENT_ENABLE) {
if (event == RCB_EVENT_ENABLE)
{
char* rptId = ReportControlBlock_getRptID(rcb);
printf(" rptID: %s\n", rptId);
char* dataSet = ReportControlBlock_getDataSet(rcb);
@ -100,6 +101,12 @@ rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection conne
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
/* Create new server configuration object */
@ -133,7 +140,7 @@ main(int argc, char** argv)
IedServerConfig_destroy(config);
/* set the identity values for MMS identify service */
IedServer_setServerIdentity(iedServer, "MZ", "basic io", "1.4.2");
IedServer_setServerIdentity(iedServer, "MZ", "basic io", "1.6.0");
/* Install handler for operate command */
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
@ -163,9 +170,10 @@ main(int argc, char** argv)
IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW);
/* MMS server will be instructed to start listening for client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
if (!IedServer_isRunning(iedServer))
{
printf("Starting server failed (maybe need root permissions or another server is already using the port)! Exit.\n");
IedServer_destroy(iedServer);
exit(-1);
@ -177,7 +185,8 @@ main(int argc, char** argv)
float t = 0.f;
while (running) {
while (running)
{
uint64_t timestamp = Hal_getTimeInMs();
t += 0.1f;

@ -126,6 +126,11 @@ int
main(int argc, char** argv)
{
iedServer = IedServer_create(&iedModel);
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlHandler) controlHandlerForBinaryOutput,
@ -169,7 +174,7 @@ main(int argc, char** argv)
IEDMODEL_GenericIO_GGIO1_SPCSO9);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -36,6 +36,12 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected,
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
/* Create new server configuration object */
@ -74,7 +80,7 @@ main(int argc, char** argv)
IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_CF, ACCESS_POLICY_ALLOW);
/* MMS server will be instructed to start listening for client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed (maybe need root permissions or another server is already using the port)! Exit.\n");

@ -55,6 +55,12 @@ fileAccessHandler (void* parameter, MmsServerConnection connection, MmsFileServi
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
iedServer = IedServer_create(&iedModel);
@ -70,7 +76,7 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -17,9 +17,6 @@
#include "logging_api.h"
LogStorage
SqliteLogStorage_createInstance(const char* filename);
static int running = 0;
static IedServer iedServer = NULL;
@ -115,9 +112,73 @@ entryDataCallback (void* parameter, const char* dataRef, const uint8_t* data, in
return true;
}
static const char*
ACSIClassToStr(ACSIClass acsiClass)
{
switch (acsiClass)
{
case ACSI_CLASS_BRCB:
return "BRCB";
case ACSI_CLASS_URCB:
return "URCB";
case ACSI_CLASS_GoCB:
return "GoCB";
case ACSI_CLASS_SGCB:
return "SGCB";
case ACSI_CLASS_LCB:
return "LCB";
case ACSI_CLASS_GsCB:
return "GsCB";
case ACSI_CLASS_LOG:
return "log";
case ACSI_CLASS_DATA_SET:
return "dataset";
case ACSI_CLASS_DATA_OBJECT:
return "data-object";
case ACSI_CLASS_MSVCB:
return "MSVCB";
case ACSI_CLASS_USVCB:
return "USVCB";
default:
return "unknown";
}
}
bool
controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, IedServer_ControlBlockAccessType accessType)
{
printf("Access to %s %s/%s.%s\n", ACSIClassToStr(acsiClass), ld->name, ln ? ln->name : "-", objectName);
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)
return true;
else
return false;
}
return true;
}
static bool
listObjectsAccessHandler(void* parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice* ld, LogicalNode* ln, const char* objectName, const char* subObjectName, FunctionalConstraint fc)
{
if (subObjectName)
printf("list objects access[2] to %s/%s.%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, subObjectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc));
else
printf("list objects access[2] to %s/%s.%s [acsi-class: %s(%i)] [FC=%s]\n", ld->name, ln ? ln->name : "-", objectName, ACSIClassToStr(acsiClass), acsiClass, FunctionalConstraint_toString(fc));
return true;
}
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
iedServer = IedServer_create(&iedModel);
@ -141,6 +202,8 @@ main(int argc, char** argv)
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
IedServer_setControlBlockAccessHandler(iedServer, controlBlockAccessHandler, NULL);
LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db");
LogStorage_setMaxLogEntries(statusLog, 10);
@ -172,9 +235,10 @@ main(int argc, char** argv)
LogStorage_getEntries(statusLog, 0, Hal_getTimeInMs(), entryCallback, (LogEntryDataCallback) entryDataCallback, NULL);
#endif
IedServer_setListObjectsAccessHandler(iedServer, listObjectsAccessHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -159,6 +159,12 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu
int main(int argc, char** argv) {
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
iedServer = IedServer_create(&iedModel);
/* Activate authentication */
@ -194,7 +200,7 @@ int main(int argc, char** argv) {
IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -97,7 +97,10 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu
{
void* securityToken = ClientConnection_getSecurityToken(connection);
printf("Read access to %s/%s.%s\n", ld->name, ln->name, dataObject->name);
if (dataObject)
printf("Read access to %s/%s.%s[%s]\n", ld->name, ln->name, dataObject->name, FunctionalConstraint_toString(fc));
else
printf("Read access to %s/%s[%s]\n", ld->name, ln->name, FunctionalConstraint_toString(fc));
return DATA_ACCESS_ERROR_SUCCESS;
}
@ -105,6 +108,12 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
IedServerConfig config = IedServerConfig_create();
//IedServerConfig_enableEditSG(config, false);
@ -112,6 +121,8 @@ main(int argc, char** argv)
iedServer = IedServer_createWithConfig(&iedModel, NULL, config);
IedServer_setTimeQuality(iedServer, true, false, false, 10);
IedServerConfig_destroy(config);
LogicalDevice* ld = IEDMODEL_PROT;
@ -127,7 +138,7 @@ main(int argc, char** argv)
IedServer_setReadAccessHandler(iedServer, readAccessHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -200,6 +200,12 @@ writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnect
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
/* Create a new IEC 61850 server instance */
@ -220,7 +226,7 @@ main(int argc, char** argv)
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_blkEna, writeAccessHandler, NULL);
/* MMS server will be instructed to start listening for client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -65,6 +65,11 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
iedServer = IedServer_create(&iedModel);
@ -86,7 +91,7 @@ main(int argc, char** argv)
IEDMODEL_GenericIO_GGIO1_SPCSO4);
/* MMS server will be instructed to start listening to client connections. */
IedServer_startThreadless(iedServer, 102);
IedServer_startThreadless(iedServer, tcpPort);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");

@ -41,10 +41,16 @@ writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnect
int
main(int argc, char** argv)
{
int tcpPort = 102;
if (argc > 1) {
tcpPort = atoi(argv[1]);
}
iedServer = IedServer_create(&iedModel);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
IedServer_start(iedServer, tcpPort);
/* Don't allow access to SP variables by default */
IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_SP, ACCESS_POLICY_DENY);

@ -30,11 +30,15 @@ reportCallbackFunction(void* parameter, ClientReport report)
}
static void
securityEventHandler(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* msg)
securityEventHandler(void* parameter, TLSEventLevel eventLevel, int eventCode, const char* msg, TLSConnection con)
{
(void)parameter;
printf("[SECURITY EVENT] %s (t: %i, c: %i)\n", msg, eventLevel, eventCode);
char* peerAddr = TLSConnection_getPeerAddress(con, NULL);
printf("[SECURITY EVENT] %s (%s)(t: %i, c: %i)\n", msg, peerAddr, eventLevel, eventCode);
free(peerAddr);
}
int main(int argc, char** argv) {

@ -103,11 +103,17 @@ clientAuthenticator(void* parameter, AcseAuthenticationParameter authParameter,
}
static void
securityEventHandler(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* msg)
securityEventHandler(void* parameter, TLSEventLevel eventLevel, int eventCode, const char* msg, TLSConnection con)
{
(void)parameter;
printf("[SECURITY EVENT] %s (t: %i, c: %i)\n", msg, eventLevel, eventCode);
char* peerAddr = TLSConnection_getPeerAddress(con, NULL);
const char* tlsVersionStr = TLSConfigVersion_toString(TLSConnection_getTLSVersion(con));
printf("[SECURITY EVENT - %s] %s (%s)(t: %i, c: %i)\n", tlsVersionStr, msg, peerAddr, eventLevel, eventCode);
free(peerAddr);
}
int

@ -0,0 +1,14 @@
#include "acse.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
AcseConnection acseConnection;
AcseConnection_init(&acseConnection, NULL, NULL, NULL);
ByteBuffer* acseBuffer = ByteBuffer_create(NULL, size);
ByteBuffer_append(acseBuffer, data, size);
AcseConnection_parseMessage(&acseConnection, acseBuffer);
ByteBuffer_destroy(acseBuffer);
return 0;
}

@ -0,0 +1,35 @@
#include <stdio.h>
#include <stdlib.h>
#include "iec61850_server.h"
#include "hal_thread.h"
#include "lib_memory.h"
int LLVMFuzzerTestOneInput(const char *data, size_t size) {
int out;
MmsValue* mmsValue = NULL;
mmsValue = MmsValue_decodeMmsData(data, 0, size, &out);
if (mmsValue == NULL) {
return 0;
}
int dataSize = MmsValue_encodeMmsData(mmsValue, NULL, 0, false);
if (dataSize <= 0) {
return 0;
}
uint8_t *mmsBuffer = (uint8_t *)GLOBAL_MALLOC(dataSize);
if (mmsBuffer == NULL) {
return 0;
}
MmsValue_encodeMmsData(mmsValue, mmsBuffer, 0, true);
GLOBAL_FREEMEM(mmsBuffer);
if (mmsValue != NULL) {
MmsValue_delete(mmsValue);
}
return 0;
}

@ -0,0 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
#include "iec61850_server.h"
#include "hal_thread.h"
#define kBufSize 4096
int LLVMFuzzerTestOneInput(const char *data, size_t size) {
int out;
MmsValue* mmsValue = NULL;
mmsValue = MmsValue_decodeMmsData(data, 0, size, &out);
if (mmsValue == NULL) {
return 0;
}
int dataSize = MmsValue_encodeMmsData(mmsValue, NULL, 0, false);
if (dataSize <= 0) {
return 0;
}
char printBuffer[kBufSize];
MmsValue_printToBuffer(mmsValue, printBuffer, kBufSize);
if (mmsValue != NULL) {
MmsValue_delete(mmsValue);
}
return 0;
}

@ -10,7 +10,7 @@ endif()
project(hal)
set(LIBHAL_VERSION_MAJOR "2")
set(LIBHAL_VERSION_MINOR "0")
set(LIBHAL_VERSION_MINOR "2")
set(LIBHAL_VERSION_PATCH "0")
# feature checks
@ -28,7 +28,7 @@ message("Found winpcap -> compile ethernet HAL layer (required for GOOSE/SV supp
set(WITH_WPCAP 1)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Include")
else()
message("winpcap not found -> skip ethernet HAL layer (no GOOSE/SV support)")
message("winpcap not found -> skip ethernet HAL layer (no L2 GOOSE/SV support)")
endif()
endif(WIN32)
@ -116,10 +116,15 @@ ENDIF(WIN32)
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" )
if(WITH_MBEDTLS)
message("Found mbedtls -> can compile HAL with TLS support")
message("Found mbedtls 2.28 -> can compile HAL with TLS 1.2 support")
set(WITH_MBEDTLS 1)
endif(WITH_MBEDTLS)
if (WITH_MBEDTLS3)
message("Found mbedtls 3.6 -> can compile HAL with TLS 1.3 support")
set(WITH_MBEDTLS3 1)
endif(WITH_MBEDTLS3)
if(WITH_MBEDTLS)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls
@ -147,6 +152,32 @@ list (APPEND libhal_SRCS ${tls_SRCS})
endif(WITH_MBEDTLS)
if(WITH_MBEDTLS3)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3
${MBEDTLS_INCLUDE_DIR}
)
if(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
link_directories(${CONFIG_EXTERNAL_MBEDTLS_DYNLIB_PATH})
else()
file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/../third_party/mbedtls/mbedtls-3.6.0/library/*.c)
endif(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h")
set (libhal_SRCS ${libhal_SRCS}
${CMAKE_CURRENT_LIST_DIR}/tls/mbedtls3/tls_mbedtls.c
)
IF(MSVC)
set_source_files_properties(${libhal_SRCS}
PROPERTIES LANGUAGE CXX)
ENDIF()
list (APPEND libhal_SRCS ${tls_SRCS})
endif(WITH_MBEDTLS3)
add_library (hal STATIC ${libhal_SRCS})
add_library (hal-shared STATIC ${libhal_SRCS})
@ -175,9 +206,15 @@ IF(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
ENDIF(CONFIG_USE_EXTERNAL_MBEDTLS_DYNLIB)
IF(MINGW)
target_link_libraries(hal ws2_32 iphlpapi)
target_link_libraries(hal ws2_32 iphlpapi bcrypt)
message("Building with MinGW")
ENDIF(MINGW)
IF (MSVC)
target_link_libraries(hal bcrypt)
target_link_libraries(hal-shared bcrypt)
ENDIF()
iF(WITH_WPCAP)
target_link_libraries(hal
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib

@ -1,7 +1,7 @@
/*
* ethernet_linux.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -57,7 +57,8 @@ EthernetHandleSet_new(void)
{
EthernetHandleSet result = (EthernetHandleSet) GLOBAL_MALLOC(sizeof(struct sEthernetHandleSet));
if (result != NULL) {
if (result != NULL)
{
result->handles = NULL;
result->nhandles = 0;
}
@ -68,8 +69,8 @@ EthernetHandleSet_new(void)
void
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
{
if (self != NULL && sock != NULL) {
if (self != NULL && sock != NULL)
{
int i = self->nhandles++;
self->handles = realloc(self->handles, self->nhandles * sizeof(struct pollfd));
@ -82,12 +83,14 @@ EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
void
EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock)
{
if ((self != NULL) && (sock != NULL)) {
if ((self != NULL) && (sock != NULL))
{
int i;
for (i = 0; i < self->nhandles; i++) {
if (self->handles[i].fd == sock->rawSocket) {
for (i = 0; i < self->nhandles; i++)
{
if (self->handles[i].fd == sock->rawSocket)
{
memmove(&self->handles[i], &self->handles[i+1], sizeof(struct pollfd) * (self->nhandles - i - 1));
self->nhandles--;
return;
@ -128,7 +131,8 @@ getInterfaceIndex(int sock, const char* deviceName)
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1)
{
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Failed to get interface index");
return -1;
@ -157,7 +161,7 @@ Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
int i;
for(i = 0; i < 6; i++ )
for (i = 0; i < 6; i++ )
{
addr[i] = (unsigned char)buffer.ifr_hwaddr.sa_data[i];
}
@ -166,106 +170,112 @@ Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
EthernetSocket
Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress)
{
EthernetSocket ethernetSocket = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket));
EthernetSocket self = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket));
if (ethernetSocket) {
ethernetSocket->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (self)
{
self->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (ethernetSocket->rawSocket == -1) {
if (self->rawSocket == -1)
{
if (DEBUG_SOCKET)
printf("Error creating raw socket!\n");
GLOBAL_FREEMEM(ethernetSocket);
GLOBAL_FREEMEM(self);
return NULL;
}
ethernetSocket->socketAddress.sll_family = PF_PACKET;
ethernetSocket->socketAddress.sll_protocol = htons(ETH_P_ALL);
self->socketAddress.sll_family = PF_PACKET;
self->socketAddress.sll_protocol = htons(ETH_P_ALL);
int ifcIdx = getInterfaceIndex(ethernetSocket->rawSocket, interfaceId);
int ifcIdx = getInterfaceIndex(self->rawSocket, interfaceId);
if (ifcIdx == -1) {
Ethernet_destroySocket(ethernetSocket);
if (ifcIdx == -1)
{
Ethernet_destroySocket(self);
return NULL;
}
ethernetSocket->socketAddress.sll_ifindex = ifcIdx;
self->socketAddress.sll_ifindex = ifcIdx;
ethernetSocket->socketAddress.sll_hatype = ARPHRD_ETHER;
ethernetSocket->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST;
self->socketAddress.sll_hatype = ARPHRD_ETHER;
self->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST;
ethernetSocket->socketAddress.sll_halen = ETH_ALEN;
self->socketAddress.sll_halen = ETH_ALEN;
memset(ethernetSocket->socketAddress.sll_addr, 0, 8);
memset(self->socketAddress.sll_addr, 0, 8);
if (destAddress != NULL)
memcpy(ethernetSocket->socketAddress.sll_addr, destAddress, 6);
memcpy(self->socketAddress.sll_addr, destAddress, 6);
ethernetSocket->isBind = false;
self->isBind = false;
Ethernet_setMode(ethernetSocket, ETHERNET_SOCKET_MODE_PROMISC);
Ethernet_setMode(self, ETHERNET_SOCKET_MODE_PROMISC);
}
return ethernetSocket;
return self;
}
void
Ethernet_setMode(EthernetSocket ethSocket, EthernetSocketMode mode)
Ethernet_setMode(EthernetSocket self, EthernetSocketMode mode)
{
if (ethSocket) {
if (mode == ETHERNET_SOCKET_MODE_PROMISC) {
if (self)
{
if (mode == ETHERNET_SOCKET_MODE_PROMISC)
{
struct ifreq ifr;
if (ioctl (ethSocket->rawSocket, SIOCGIFFLAGS, &ifr) == -1)
if (ioctl (self->rawSocket, SIOCGIFFLAGS, &ifr) == -1)
{
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Problem getting device flags");
return;
}
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (ethSocket->rawSocket, SIOCSIFFLAGS, &ifr) == -1)
if (ioctl (self->rawSocket, SIOCSIFFLAGS, &ifr) == -1)
{
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Setting device to promiscuous mode failed");
return;
}
}
else if (mode == ETHERNET_SOCKET_MODE_ALL_MULTICAST) {
else if (mode == ETHERNET_SOCKET_MODE_ALL_MULTICAST)
{
struct ifreq ifr;
if (ioctl (ethSocket->rawSocket, SIOCGIFFLAGS, &ifr) == -1)
if (ioctl (self->rawSocket, SIOCGIFFLAGS, &ifr) == -1)
{
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Problem getting device flags");
return;
}
ifr.ifr_flags |= IFF_ALLMULTI;
if (ioctl (ethSocket->rawSocket, SIOCSIFFLAGS, &ifr) == -1)
if (ioctl (self->rawSocket, SIOCSIFFLAGS, &ifr) == -1)
{
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Setting device to promiscuous mode failed");
return;
}
}
else if (mode == ETHERNET_SOCKET_MODE_HOST_ONLY) {
ethSocket->socketAddress.sll_pkttype = PACKET_HOST;
else if (mode == ETHERNET_SOCKET_MODE_HOST_ONLY)
{
self->socketAddress.sll_pkttype = PACKET_HOST;
}
else if (mode == ETHERNET_SOCKET_MODE_MULTICAST) {
ethSocket->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST;
else if (mode == ETHERNET_SOCKET_MODE_MULTICAST)
{
self->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST;
}
}
}
void
Ethernet_addMulticastAddress(EthernetSocket ethSocket, uint8_t* multicastAddress)
Ethernet_addMulticastAddress(EthernetSocket self, uint8_t* multicastAddress)
{
struct packet_mreq mreq;
mreq.mr_ifindex = ethSocket->socketAddress.sll_ifindex;
memset(&mreq, 0, sizeof(struct packet_mreq));
mreq.mr_ifindex = self->socketAddress.sll_ifindex;
mreq.mr_alen = ETH_ALEN;
mreq.mr_type = PACKET_MR_MULTICAST;
mreq.mr_address[0] = multicastAddress[0];
@ -275,17 +285,17 @@ Ethernet_addMulticastAddress(EthernetSocket ethSocket, uint8_t* multicastAddress
mreq.mr_address[4] = multicastAddress[4];
mreq.mr_address[5] = multicastAddress[5];
int res = setsockopt(ethSocket->rawSocket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
int res = setsockopt(self->rawSocket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
if (res != 0) {
if (res != 0)
{
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Setting multicast address failed");
}
}
void
Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType)
Ethernet_setProtocolFilter(EthernetSocket self, uint16_t etherType)
{
if (etherType == 0x88b8)
{
@ -303,22 +313,22 @@ Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType)
fprog.len = sizeof(filter) / sizeof(*filter);
fprog.filter = filter;
if (setsockopt(ethSocket->rawSocket, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) == -1)
if (setsockopt(self->rawSocket, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) == -1)
if (DEBUG_SOCKET)
printf("ETHERNET_LINUX: Applying filter failed");
}
else
{
ethSocket->socketAddress.sll_protocol = htons(etherType);
self->socketAddress.sll_protocol = htons(etherType);
}
}
/* non-blocking receive */
int
Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
{
if (self->isBind == false) {
if (self->isBind == false)
{
if (bind(self->rawSocket, (struct sockaddr*) &self->socketAddress, sizeof(self->socketAddress)) == 0)
self->isBind = true;
else
@ -329,17 +339,20 @@ Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
}
void
Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize)
Ethernet_sendPacket(EthernetSocket self, uint8_t* buffer, int packetSize)
{
sendto(ethSocket->rawSocket, buffer, packetSize,
0, (struct sockaddr*) &(ethSocket->socketAddress), sizeof(ethSocket->socketAddress));
sendto(self->rawSocket, buffer, packetSize,
0, (struct sockaddr*) &(self->socketAddress), sizeof(self->socketAddress));
}
void
Ethernet_destroySocket(EthernetSocket ethSocket)
Ethernet_destroySocket(EthernetSocket self)
{
close(ethSocket->rawSocket);
GLOBAL_FREEMEM(ethSocket);
if (self)
{
close(self->rawSocket);
GLOBAL_FREEMEM(self);
}
}
bool
@ -347,4 +360,3 @@ Ethernet_isSupported()
{
return true;
}

@ -53,13 +53,13 @@ FileSystem_openFile(char* fileName, bool readWrite)
int
FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize)
{
return fread(buffer, maxSize, 1, (FILE*) handle);
return fread(buffer, 1, maxSize, (FILE*) handle);
}
int
FileSystem_writeFile(FileHandle handle, uint8_t* buffer, int size)
{
return fwrite(buffer, size, 1, (FILE*) handle);
return fwrite(buffer, 1, size, (FILE*) handle);
}
void

@ -62,13 +62,13 @@ FileSystem_openFile(char* fileName, bool readWrite)
int
FileSystem_readFile(FileHandle handle, uint8_t* buffer, int maxSize)
{
return fread(buffer, maxSize, 1, (FILE*) handle);
return fread(buffer, 1, maxSize, (FILE*) handle);
}
int
FileSystem_writeFile(FileHandle handle, uint8_t* buffer, int size)
{
return fwrite(buffer, size, 1, (FILE*) handle);
return fwrite(buffer, 1, size, (FILE*) handle);
}
void

@ -1,7 +1,7 @@
/*
* socket_hal.h
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
@ -357,7 +357,7 @@ Socket_getPeerAddress(Socket self);
*
* The peer address has to be returned as null terminated string
*
* Implementation of this function is MANDATORY (lib60870)
* Implementation of this function is MANDATORY (lib60870 and libiec61850)
*
* \param self the client, connection or server socket instance
* \param peerAddressString a string to store the peer address (the string should have space

@ -1,7 +1,7 @@
/*
* time.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
@ -68,6 +68,22 @@ Hal_getTimeInNs(void);
PAL_API bool
Hal_setTimeInNs(nsSinceEpoch nsTime);
/**
* Get the monotonic time or system tick time in ms
*
* \return the system time with millisecond resolution.
*/
PAL_API msSinceEpoch
Hal_getMonotonicTimeInMs(void);
/**
* Get the monotonic time or system tick in nanoseconds.
*
* \return the system time with nanosecond resolution.
*/
PAL_API nsSinceEpoch
Hal_getMonotonicTimeInNs(void);
/*! @} */
/*! @} */

@ -0,0 +1,262 @@
#ifndef IANA_TLS_CIPHER_SUITES_H_
#define IANA_TLS_CIPHER_SUITES_H_
#ifdef __cplusplus
extern "C" {
#endif
#define TLS_NULL_WITH_NULL_NULL 0x0000
#define TLS_RSA_WITH_NULL_MD5 0x0001
#define TLS_RSA_WITH_NULL_SHA 0x0002
#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003
#define TLS_RSA_WITH_RC4_128_MD5 0x0004
#define TLS_RSA_WITH_RC4_128_SHA 0x0005
#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006
#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007
#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008
#define TLS_RSA_WITH_DES_CBC_SHA 0x0009
#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A
#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B
#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C
#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D
#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E
#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F
#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010
#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011
#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012
#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013
#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014
#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015
#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016
#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017
#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018
#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019
#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A
#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B
#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F
#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030
#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031
#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034
#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036
#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037
#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A
#define TLS_RSA_WITH_NULL_SHA256 0x003B
#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C
#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D
#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E
#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F
#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040
#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0041
#define TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x0042
#define TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0043
#define TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x0044
#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x0045
#define TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA 0x0046
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068
#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069
#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B
#define TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C
#define TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D
#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0084
#define TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x0085
#define TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0086
#define TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x0087
#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x0088
#define TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA 0x0089
#define TLS_RSA_WITH_SEED_CBC_SHA 0x0096
#define TLS_DH_DSS_WITH_SEED_CBC_SHA 0x0097
#define TLS_DH_RSA_WITH_SEED_CBC_SHA 0x0098
#define TLS_DHE_DSS_WITH_SEED_CBC_SHA 0x0099
#define TLS_DHE_RSA_WITH_SEED_CBC_SHA 0x009A
#define TLS_DH_anon_WITH_SEED_CBC_SHA 0x009B
#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C
#define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D
#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E
#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F
#define TLS_DH_RSA_WITH_AES_128_GCM_SHA256 0x00A0
#define TLS_DH_RSA_WITH_AES_256_GCM_SHA384 0x00A1
#define TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2
#define TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 0x00A3
#define TLS_DH_DSS_WITH_AES_128_GCM_SHA256 0x00A4
#define TLS_DH_DSS_WITH_AES_256_GCM_SHA384 0x00A5
#define TLS_DH_anon_WITH_AES_128_GCM_SHA256 0x00A6
#define TLS_DH_anon_WITH_AES_256_GCM_SHA384 0x00A7
#define TLS_PSK_WITH_AES_128_CBC_SHA 0x008C
#define TLS_PSK_WITH_AES_256_CBC_SHA 0x008D
#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA 0x008E
#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA 0x008F
#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA 0x0090
#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA 0x0091
#define TLS_PSK_WITH_AES_128_CBC_SHA256 0x00AE
#define TLS_PSK_WITH_AES_256_CBC_SHA384 0x00AF
#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 0x00B0
#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 0x00B1
#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 0x00B2
#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 0x00B3
#define TLS_PSK_WITH_NULL_SHA 0x002C
#define TLS_DHE_PSK_WITH_NULL_SHA 0x002D
#define TLS_RSA_PSK_WITH_NULL_SHA 0x002E
#define TLS_PSK_WITH_NULL_SHA256 0x00B4
#define TLS_PSK_WITH_NULL_SHA384 0x00B5
#define TLS_DHE_PSK_WITH_NULL_SHA256 0x00B6
#define TLS_DHE_PSK_WITH_NULL_SHA384 0x00B7
#define TLS_RSA_PSK_WITH_NULL_SHA256 0x00B8
#define TLS_RSA_PSK_WITH_NULL_SHA384 0x00B9
#define TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001
#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002
#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003
#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004
#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005
#define TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006
#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007
#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A
#define TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B
#define TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C
#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D
#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E
#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F
#define TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010
#define TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011
#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013
#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014
#define TLS_ECDH_anon_WITH_NULL_SHA 0xC015
#define TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016
#define TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017
#define TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018
#define TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024
#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025
#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028
#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029
#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A
#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C
#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D
#define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E
#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031
#define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032
#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA 0xC035
#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA 0xC036
#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0xC037
#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0xC038
#define TLS_ECDHE_PSK_WITH_NULL_SHA 0xC039
#define TLS_ECDHE_PSK_WITH_NULL_SHA256 0xC03A
#define TLS_ECDHE_PSK_WITH_NULL_SHA384 0xC03B
#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC072
#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC073
#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC074
#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC075
#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC076
#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC077
#define TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC078
#define TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC079
#define TLS_RSA_WITH_ARIA_128_CBC_SHA256 0xC03C
#define TLS_RSA_WITH_ARIA_256_CBC_SHA384 0xC03D
#define TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 0xC03E
#define TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 0xC03F
#define TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 0xC040
#define TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 0xC041
#define TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 0xC042
#define TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 0xC043
#define TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 0xC044
#define TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 0xC045
#define TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 0xC046
#define TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 0xC047
#define TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 0xC048
#define TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 0xC049
#define TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 0xC04A
#define TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 0xC04B
#define TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 0xC04C
#define TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 0xC04D
#define TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 0xC04E
#define TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 0xC04F
#define TLS_RSA_WITH_ARIA_128_GCM_SHA256 0xC050
#define TLS_RSA_WITH_ARIA_256_GCM_SHA384 0xC051
#define TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 0xC052
#define TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 0xC053
#define TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 0xC054
#define TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 0xC055
#define TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 0xC056
#define TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 0xC057
#define TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 0xC058
#define TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 0xC059
#define TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 0xC05A
#define TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 0xC05B
#define TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 0xC05C
#define TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 0xC05D
#define TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 0xC05E
#define TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 0xC05F
#define TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 0xC060
#define TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 0xC061
#define TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 0xC062
#define TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 0xC063
#define TLS_PSK_WITH_ARIA_128_CBC_SHA256 0xC064
#define TLS_PSK_WITH_ARIA_256_CBC_SHA384 0xC065
#define TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 0xC066
#define TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 0xC067
#define TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 0xC068
#define TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 0xC069
#define TLS_PSK_WITH_ARIA_128_GCM_SHA256 0xC06A
#define TLS_PSK_WITH_ARIA_256_GCM_SHA384 0xC06B
#define TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 0xC06C
#define TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 0xC06D
#define TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 0xC06E
#define TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 0xC06F
#define TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 0xC070
#define TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 0xC071
#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC076
#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC077
#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC078
#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC079
#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07A
#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07B
#define TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07C
#define TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07D
#define TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC07E
#define TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC07F
#define TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC080
#define TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC081
#define TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC082
#define TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC083
#define TLS_ECDHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC084
#define TLS_ECDHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC085
#define TLS_RSA_WITH_AES_128_CCM 0xC09C
#define TLS_RSA_WITH_AES_256_CCM 0xC09D
#define TLS_DHE_RSA_WITH_AES_128_CCM 0xC09E
#define TLS_DHE_RSA_WITH_AES_256_CCM 0xC09F
#define TLS_RSA_WITH_AES_128_CCM_8 0xC0A0
#define TLS_RSA_WITH_AES_256_CCM_8 0xC0A1
#define TLS_DHE_RSA_WITH_AES_128_CCM_8 0xC0A2
#define TLS_DHE_RSA_WITH_AES_256_CCM_8 0xC0A3
#define TLS_PSK_WITH_AES_128_CCM 0xC0A4
#define TLS_PSK_WITH_AES_256_CCM 0xC0A5
#define TLS_DHE_PSK_WITH_AES_128_CCM 0xC0A6
#define TLS_DHE_PSK_WITH_AES_256_CCM 0xC0A7
#define TLS_PSK_WITH_AES_128_CCM_8 0xC0A8
#define TLS_PSK_WITH_AES_256_CCM_8 0xC0A9
#define TLS_PSK_DHE_WITH_AES_128_CCM_8 0xC0AA
#define TLS_PSK_DHE_WITH_AES_256_CCM_8 0xC0AB
#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC
// ... add more cipher suite codes here ...
#ifdef __cplusplus
}
#endif
#endif /* IANA_TLS_CIPHER_SUITES_H_ */

@ -3,7 +3,7 @@
*
* TLS Configuration API for protocol stacks using TCP/IP
*
* Copyright 2017-2021 Michael Zillgith
* Copyright 2017-2024 Michael Zillgith
*
* Abstraction layer for configuration of different TLS implementations
*
@ -17,6 +17,7 @@ extern "C" {
#endif
#include "hal_base.h"
#include "tls_ciphers.h"
/**
* \file tls_config.h
@ -50,11 +51,30 @@ TLSConfiguration_create(void);
PAL_API void
TLSConfiguration_setClientMode(TLSConfiguration self);
typedef enum {
TLS_VERSION_NOT_SELECTED = 0,
TLS_VERSION_SSL_3_0 = 3,
TLS_VERSION_TLS_1_0 = 4,
TLS_VERSION_TLS_1_1 = 5,
TLS_VERSION_TLS_1_2 = 6,
TLS_VERSION_TLS_1_3 = 7
} TLSConfigVersion;
/**
* \brief Convert TLS version number to string
*
* \param version TLS version number
*
* \return the TLS version as null terminated string
*/
PAL_API const char*
TLSConfigVersion_toString(TLSConfigVersion version);
typedef enum {
TLS_SEC_EVT_INFO = 0,
TLS_SEC_EVT_WARNING = 1,
TLS_SEC_EVT_INCIDENT = 2
} TLSConfiguration_EventLevel;
} TLSEventLevel;
#define TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED 1
#define TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION 2
@ -69,12 +89,55 @@ typedef enum {
#define TLS_EVENT_CODE_ALM_CERT_EXPIRED 11
#define TLS_EVENT_CODE_ALM_CERT_REVOKED 12
#define TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED 13
#define TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED 12
#define TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED 14
#define TLS_EVENT_CODE_ALM_NO_CIPHER 15
#define TLS_EVENT_CODE_INF_SESSION_ESTABLISHED 16
#define TLS_EVENT_CODE_WRN_CERT_EXPIRED 17
#define TLS_EVENT_CODE_WRN_CERT_NOT_YET_VALID 18
#define TLS_EVENT_CODE_WRN_CRL_EXPIRED 19
#define TLS_EVENT_CODE_WRN_CRL_NOT_YET_VALID 20
typedef struct sTLSConnection* TLSConnection;
/**
* \brief Get the peer address of the TLS connection
*
* \param self the TLS connection instance
* \param peerAddrBuf user provided buffer that can hold at least 60 characters, or NULL to allow the function to allocate the memory for the buffer
*
* \returns peer address:port as null terminated string
*/
PAL_API char*
TLSConnection_getPeerAddress(TLSConnection self, char* peerAddrBuf);
/**
* \brief Get the TLS certificate used by the peer
*
* \param self the TLS connection instance
* \param certSize[OUT] the certificate size in bytes
*
* \return address of the certificate buffer
*/
PAL_API uint8_t*
TLSConnection_getPeerCertificate(TLSConnection self, int* certSize);
/**
* \brief Get the TLS version used by the connection
*
* \param self the TLS connection instance
*
* \return TLS version
*/
PAL_API TLSConfigVersion
TLSConnection_getTLSVersion(TLSConnection self);
typedef void (*TLSConfiguration_EventHandler)(void* parameter, TLSConfiguration_EventLevel eventLevel, int eventCode, const char* message);
typedef void (*TLSConfiguration_EventHandler)(void* parameter, TLSEventLevel eventLevel, int eventCode, const char* message, TLSConnection con);
/**
* \brief Set the security event handler
*
* \param handler the security event callback handler
* \param parameter user provided parameter to be passed to the callback handler
*/
PAL_API void
TLSConfiguration_setEventHandler(TLSConfiguration self, TLSConfiguration_EventHandler handler, void* parameter);
@ -106,6 +169,14 @@ TLSConfiguration_setSessionResumptionInterval(TLSConfiguration self, int interva
PAL_API void
TLSConfiguration_setChainValidation(TLSConfiguration self, bool value);
/**
* \brief Enabled or disables the verification of validity times for certificates and CRLs
*
* \param value true to enable time validation, false to disable (enabled by default)
*/
PAL_API void
TLSConfiguration_setTimeValidation(TLSConfiguration self, bool value);
/**
* \brief Set if only known certificates are accepted.
*
@ -209,15 +280,6 @@ TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* fil
PAL_API void
TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs);
typedef enum {
TLS_VERSION_NOT_SELECTED = 0,
TLS_VERSION_SSL_3_0 = 3,
TLS_VERSION_TLS_1_0 = 4,
TLS_VERSION_TLS_1_1 = 5,
TLS_VERSION_TLS_1_2 = 6,
TLS_VERSION_TLS_1_3 = 7
} TLSConfigVersion;
/**
* \brief Set minimal allowed TLS version to use
*/
@ -249,6 +311,29 @@ TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen);
PAL_API bool
TLSConfiguration_addCRLFromFile(TLSConfiguration self, const char* filename);
/**
* \brief Removes any CRL (certificate revocation list) currently in use
*/
PAL_API void
TLSConfiguration_resetCRL(TLSConfiguration self);
/**
* \brief Add an allowed ciphersuite to the list of allowed ciphersuites
*
* \param self the TLS configuration instance
* \param ciphersuite the ciphersuite to add (IANA cipher suite ID)
*/
PAL_API void
TLSConfiguration_addCipherSuite(TLSConfiguration self, int ciphersuite);
/**
* \brief Clear the list of allowed ciphersuites
*
* \param self the TLS configuration instance
*/
PAL_API void
TLSConfiguration_clearCipherSuiteList(TLSConfiguration self);
/**
* Release all resource allocated by the TLSConfiguration instance
*

@ -38,7 +38,6 @@ Memory_malloc(size_t size)
return memory;
}
void*
Memory_calloc(size_t nmemb, size_t size)
{
@ -50,7 +49,6 @@ Memory_calloc(size_t nmemb, size_t size)
return memory;
}
void *
Memory_realloc(void *ptr, size_t size)
{

@ -17,6 +17,7 @@
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>
#include <poll.h>
#include "hal_serial.h"
#include "hal_time.h"
@ -29,11 +30,10 @@ struct sSerialPort {
char parity;
uint8_t stopBits;
uint64_t lastSentTime;
struct timeval timeout;
int timeout;
SerialPortError lastError;
};
SerialPort
SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, char parity, uint8_t stopBits)
{
@ -46,8 +46,7 @@ SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, cha
self->stopBits = stopBits;
self->parity = parity;
self->lastSentTime = 0;
self->timeout.tv_sec = 0;
self->timeout.tv_usec = 100000; /* 100 ms */
self->timeout = 100; /* 100 ms */
strncpy(self->interfaceName, interfaceName, 99);
self->lastError = SERIAL_PORT_ERROR_NONE;
}
@ -212,8 +211,7 @@ SerialPort_discardInBuffer(SerialPort self)
void
SerialPort_setTimeout(SerialPort self, int timeout)
{
self->timeout.tv_sec = timeout / 1000;
self->timeout.tv_usec = (timeout % 1000) * 1000;
self->timeout = timeout;
}
SerialPortError
@ -226,14 +224,14 @@ int
SerialPort_readByte(SerialPort self)
{
uint8_t buf[1];
fd_set set;
struct pollfd fds[1];
self->lastError = SERIAL_PORT_ERROR_NONE;
FD_ZERO(&set);
FD_SET(self->fd, &set);
fds[0].fd = self->fd;
fds[0].events = POLLIN;
int ret = select(self->fd + 1, &set, NULL, NULL, &(self->timeout));
int ret = poll(fds, 1, self->timeout);
if (ret == -1) {
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;

@ -1,33 +1,33 @@
/*
* socket_bsd.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
*/
#include "hal_socket.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/tcp.h> // required for TCP keepalive
#include <signal.h>
#include <poll.h>
#include <signal.h>
#include "linked_list.h"
#include "hal_thread.h"
#include "lib_memory.h"
#include "linked_list.h"
#ifndef DEBUG_SOCKET
#define DEBUG_SOCKET 0
@ -41,22 +41,26 @@
#define MSG_NOSIGNAL 0
#endif
struct sSocket {
struct sSocket
{
int fd;
uint32_t connectTimeout;
};
struct sServerSocket {
struct sServerSocket
{
int fd;
int backLog;
};
struct sUdpSocket {
struct sUdpSocket
{
int fd;
int namespace; /* IPv4: AF_INET; IPv6: AF_INET6 */
};
struct sHandleSet {
struct sHandleSet
{
LinkedList sockets;
bool pollfdIsUpdated;
struct pollfd* fds;
@ -66,9 +70,10 @@ struct sHandleSet {
HandleSet
Handleset_new(void)
{
HandleSet self = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
HandleSet self = (HandleSet)GLOBAL_MALLOC(sizeof(struct sHandleSet));
if (self) {
if (self)
{
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
self->fds = NULL;
@ -81,8 +86,10 @@ Handleset_new(void)
void
Handleset_reset(HandleSet self)
{
if (self) {
if (self->sockets) {
if (self)
{
if (self->sockets)
{
LinkedList_destroyStatic(self->sockets);
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
@ -93,7 +100,8 @@ Handleset_reset(HandleSet self)
void
Handleset_addSocket(HandleSet self, const Socket sock)
{
if (self != NULL && sock != NULL && sock->fd != -1) {
if (self != NULL && sock != NULL && sock->fd != -1)
{
LinkedList_add(self->sockets, sock);
self->pollfdIsUpdated = false;
}
@ -102,7 +110,8 @@ Handleset_addSocket(HandleSet self, const Socket sock)
void
Handleset_removeSocket(HandleSet self, const Socket sock)
{
if (self && self->sockets && sock) {
if (self && self->sockets && sock)
{
LinkedList_remove(self->sockets, sock);
self->pollfdIsUpdated = false;
}
@ -112,8 +121,10 @@ int
Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
{
/* check if pollfd array is updated */
if (self->pollfdIsUpdated == false) {
if (self->fds) {
if (self->pollfdIsUpdated == false)
{
if (self->fds)
{
GLOBAL_FREEMEM(self->fds);
self->fds = NULL;
}
@ -124,13 +135,16 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
int i;
for (i = 0; i < self->nfds; i++) {
for (i = 0; i < self->nfds; i++)
{
LinkedList sockElem = LinkedList_get(self->sockets, i);
if (sockElem) {
Socket sock = (Socket) LinkedList_getData(sockElem);
if (sockElem)
{
Socket sock = (Socket)LinkedList_getData(sockElem);
if (sock) {
if (sock)
{
self->fds[i].fd = sock->fd;
self->fds[i].events = POLL_IN;
}
@ -140,17 +154,20 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
self->pollfdIsUpdated = true;
}
if (self->fds && self->nfds > 0) {
if (self->fds && self->nfds > 0)
{
int result = poll(self->fds, self->nfds, timeoutMs);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: poll error (errno: %i)\n", errno);
}
return result;
}
else {
else
{
/* there is no socket to wait for */
return 0;
}
@ -159,7 +176,8 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
void
Handleset_destroy(HandleSet self)
{
if (self) {
if (self)
{
if (self->sockets)
LinkedList_destroyStatic(self->sockets);
@ -197,18 +215,20 @@ static bool
prepareAddress(const char* address, int port, struct sockaddr_in* sockaddr)
{
memset((char *) sockaddr , 0, sizeof(struct sockaddr_in));
memset((char*)sockaddr, 0, sizeof(struct sockaddr_in));
if (address != NULL) {
struct hostent *server;
server = gethostbyname(address);
if (address != NULL)
{
struct hostent* server;
server = gethostbyname(address);
if (server == NULL) return false;
if (server == NULL)
return false;
memcpy((char *) &sockaddr->sin_addr.s_addr, (char *) server->h_addr, server->h_length);
}
else
sockaddr->sin_addr.s_addr = htonl(INADDR_ANY);
memcpy((char*)&sockaddr->sin_addr.s_addr, (char*)server->h_addr, server->h_length);
}
else
sockaddr->sin_addr.s_addr = htonl(INADDR_ANY);
sockaddr->sin_family = AF_INET;
sockaddr->sin_port = htons(port);
@ -228,7 +248,7 @@ 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));
setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
}
ServerSocket
@ -238,27 +258,31 @@ TcpServerSocket_create(const char* address, int port)
int fd;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
{
struct sockaddr_in serverAddress;
if (!prepareAddress(address, port, &serverAddress)) {
if (!prepareAddress(address, port, &serverAddress))
{
close(fd);
return NULL;
}
int optionReuseAddr = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optionReuseAddr, sizeof(int));
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket));
if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) >= 0)
{
serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd;
serverSocket->backLog = 2;
setSocketNonBlocking((Socket) serverSocket);
setSocketNonBlocking((Socket)serverSocket);
}
else {
else
{
close(fd);
return NULL ;
return NULL;
}
}
@ -271,7 +295,6 @@ 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)
@ -280,19 +303,22 @@ ServerSocket_accept(ServerSocket self)
Socket conSocket = NULL;
fd = accept(self->fd, NULL, NULL );
fd = accept(self->fd, NULL, NULL);
if (fd >= 0) {
conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (fd >= 0)
{
conSocket = (Socket)GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (conSocket) {
if (conSocket)
{
conSocket->fd = fd;
setSocketNonBlocking(conSocket);
activateTcpNoDelay(conSocket);
}
else {
else
{
/* out of memory */
close(fd);
@ -313,7 +339,8 @@ ServerSocket_setBacklog(ServerSocket self, int backlog)
static void
closeAndShutdownSocket(int socketFd)
{
if (socketFd != -1) {
if (socketFd != -1)
{
if (DEBUG_SOCKET)
printf("socket_linux.c: call shutdown for %i!\n", socketFd);
@ -346,10 +373,12 @@ TcpSocket_create()
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (Socket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->connectTimeout = 5000;
@ -358,7 +387,8 @@ TcpSocket_create()
int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
#endif
}
else {
else
{
/* out of memory */
close(sock);
@ -366,7 +396,8 @@ TcpSocket_create()
printf("SOCKET: out of memory\n");
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create socket (errno=%i)\n", errno);
}
@ -390,7 +421,8 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind TCP socket (errno=%i)\n", errno);
@ -398,7 +430,7 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
self->fd = -1;
return false;
}
}
return true;
}
@ -422,9 +454,11 @@ Socket_connectAsync(Socket self, const char* address, int port)
fcntl(self->fd, F_SETFL, O_NONBLOCK);
if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
if (connect(self->fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0)
{
if (errno != EINPROGRESS) {
if (errno != EINPROGRESS)
{
self->fd = -1;
return false;
}
@ -444,16 +478,18 @@ Socket_checkAsyncConnectState(Socket self)
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
int selectVal = select(self->fd + 1, NULL, &fdSet , NULL, &timeout);
int selectVal = select(self->fd + 1, NULL, &fdSet, NULL, &timeout);
if (selectVal == 1) {
if (selectVal == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return SOCKET_STATE_CONNECTED;
@ -461,10 +497,12 @@ Socket_checkAsyncConnectState(Socket self)
return SOCKET_STATE_FAILED;
}
else if (selectVal == 0) {
else if (selectVal == 0)
{
return SOCKET_STATE_CONNECTING;
}
else {
else
{
return SOCKET_STATE_FAILED;
}
}
@ -483,21 +521,23 @@ Socket_connect(Socket self, const char* address, int port)
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
if (select(self->fd + 1, NULL, &fdSet , NULL, &timeout) == 1) {
if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return true;
}
}
close (self->fd);
close(self->fd);
self->fd = -1;
return false;
@ -511,22 +551,24 @@ convertAddressToStr(struct sockaddr_storage* addr)
bool isIPv6;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) addr;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) addr;
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9);
char* clientConnection = (char*)GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
sprintf(clientConnection, "[%s]:%i", addrString, port);
@ -542,7 +584,8 @@ Socket_getPeerAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getpeername(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -555,7 +598,8 @@ Socket_getLocalAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getsockname(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getsockname(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -568,27 +612,29 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
getpeername(self->fd, (struct sockaddr*) &addr, &addrLen);
getpeername(self->fd, (struct sockaddr*)&addr, &addrLen);
char addrString[INET6_ADDRSTRLEN + 7];
int port;
bool isIPv6;
if (addr.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr;
if (addr.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr;
else if (addr.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
if (isIPv6)
sprintf(peerAddressString, "[%s]:%i", addrString, port);
@ -609,18 +655,20 @@ Socket_read(Socket self, uint8_t* buf, int size)
if (read_bytes == 0)
return -1;
if (read_bytes == -1) {
if (read_bytes == -1)
{
int error = errno;
switch (error) {
switch (error)
{
case EAGAIN:
return 0;
case EBADF:
return -1;
case EAGAIN:
return 0;
case EBADF:
return -1;
default:
return -1;
default:
return -1;
}
}
@ -663,21 +711,25 @@ UdpSocket_createUsingNamespace(int namespace)
int sock = socket(namespace, SOCK_DGRAM, IPPROTO_UDP);
if (sock != -1) {
self = (UdpSocket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (UdpSocket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->namespace = namespace;
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to allocate memory\n");
close(sock);
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create UDP socket (errno=%i)\n", errno);
}
@ -700,36 +752,42 @@ UdpSocket_createIpV6()
bool
UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
{
if (self->namespace == AF_INET) {
if (self->namespace == AF_INET)
{
struct ip_mreq mreq;
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr))) {
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr)))
{
printf("SOCKET: Invalid IPv4 multicast address\n");
return false;
}
else {
else
{
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", errno);
return false;
}
}
return true;
}
else if (self->namespace == AF_INET6) {
else if (self->namespace == AF_INET6)
{
struct ipv6_mreq mreq;
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1) {
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
mreq.ipv6mr_interface = 0;
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
@ -743,16 +801,20 @@ UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
bool
UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
{
if (self->namespace == AF_INET) {
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
if (self->namespace == AF_INET)
{
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", errno);
return false;
}
return true;
}
else if (self->namespace == AF_INET6) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
else if (self->namespace == AF_INET6)
{
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", errno);
return false;
}
@ -766,10 +828,11 @@ UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
bool
UdpSocket_bind(UdpSocket self, const char* address, int port)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in localAddress;
if (!prepareAddress(address, port, &localAddress)) {
if (!prepareAddress(address, port, &localAddress))
{
close(self->fd);
self->fd = 0;
return false;
@ -777,7 +840,8 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind UDP socket (errno=%i)\n", errno);
@ -793,10 +857,11 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
bool
UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in remoteAddress;
if (!prepareAddress(address, port, &remoteAddress)) {
if (!prepareAddress(address, port, &remoteAddress))
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address);
@ -806,14 +871,17 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int result = sendto(self->fd, msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress));
if (result == msgSize) {
if (result == msgSize)
{
return true;
}
else if (result == -1) {
else if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (errno=%i)\n", errno);
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (insufficient data sent)\n");
}
@ -824,31 +892,35 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int
UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_storage remoteAddress;
socklen_t structSize = sizeof(struct sockaddr_storage);
int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno);
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
@ -862,19 +934,22 @@ UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* m
snprintf(address, maxAddrSize, "%s:%i", addrString, port);
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;

@ -1,56 +1,59 @@
/*
* socket_linux.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
*/
#include "hal_socket.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <netinet/tcp.h> /* required for TCP keepalive */
#include <linux/version.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h> /* required for TCP keepalive */
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <signal.h>
#include <poll.h>
#include <signal.h>
#include "linked_list.h"
#include "hal_thread.h"
#include "lib_memory.h"
#include "linked_list.h"
#ifndef DEBUG_SOCKET
#define DEBUG_SOCKET 0
#endif
struct sSocket {
struct sSocket
{
int fd;
uint32_t connectTimeout;
};
struct sServerSocket {
struct sServerSocket
{
int fd;
int backLog;
};
struct sUdpSocket {
struct sUdpSocket
{
int fd;
int namespace; /* IPv4: AF_INET; IPv6: AF_INET6 */
};
struct sHandleSet {
struct sHandleSet
{
LinkedList sockets;
bool pollfdIsUpdated;
struct pollfd* fds;
@ -60,23 +63,26 @@ struct sHandleSet {
HandleSet
Handleset_new(void)
{
HandleSet self = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
HandleSet self = (HandleSet)GLOBAL_MALLOC(sizeof(struct sHandleSet));
if (self) {
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
self->fds = NULL;
self->nfds = 0;
}
if (self)
{
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
self->fds = NULL;
self->nfds = 0;
}
return self;
return self;
}
void
Handleset_reset(HandleSet self)
{
if (self) {
if (self->sockets) {
if (self)
{
if (self->sockets)
{
LinkedList_destroyStatic(self->sockets);
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
@ -87,17 +93,19 @@ Handleset_reset(HandleSet self)
void
Handleset_addSocket(HandleSet self, const Socket sock)
{
if (self != NULL && sock != NULL && sock->fd != -1) {
if (self != NULL && sock != NULL && sock->fd != -1)
{
LinkedList_add(self->sockets, sock);
self->pollfdIsUpdated = false;
}
LinkedList_add(self->sockets, sock);
self->pollfdIsUpdated = false;
}
}
void
Handleset_removeSocket(HandleSet self, const Socket sock)
{
if (self && self->sockets && sock) {
if (self && self->sockets && sock)
{
LinkedList_remove(self->sockets, sock);
self->pollfdIsUpdated = false;
}
@ -107,8 +115,10 @@ int
Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
{
/* check if pollfd array is updated */
if (self->pollfdIsUpdated == false) {
if (self->fds) {
if (self->pollfdIsUpdated == false)
{
if (self->fds)
{
GLOBAL_FREEMEM(self->fds);
self->fds = NULL;
}
@ -119,13 +129,16 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
int i;
for (i = 0; i < self->nfds; i++) {
for (i = 0; i < self->nfds; i++)
{
LinkedList sockElem = LinkedList_get(self->sockets, i);
if (sockElem) {
Socket sock = (Socket) LinkedList_getData(sockElem);
if (sockElem)
{
Socket sock = (Socket)LinkedList_getData(sockElem);
if (sock) {
if (sock)
{
self->fds[i].fd = sock->fd;
self->fds[i].events = POLL_IN;
}
@ -135,21 +148,25 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
self->pollfdIsUpdated = true;
}
if (self->fds && self->nfds > 0) {
if (self->fds && self->nfds > 0)
{
int result = poll(self->fds, self->nfds, timeoutMs);
if (result == -1 && errno == EINTR) {
if (result == -1 && errno == EINTR)
{
result = 0;
}
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: poll error (errno: %i)\n", errno);
}
return result;
}
else {
else
{
/* there is no socket to wait for */
return 0;
}
@ -158,7 +175,8 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
void
Handleset_destroy(HandleSet self)
{
if (self) {
if (self)
{
if (self->sockets)
LinkedList_destroyStatic(self->sockets);
@ -178,26 +196,30 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count)
optval = 1;
if (setsockopt(self->fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen)) {
if (setsockopt(self->fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to enable TCP keepalive\n");
}
#if defined TCP_KEEPCNT
optval = idleTime;
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen)) {
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to set TCP keepalive TCP_KEEPIDLE parameter\n");
}
optval = interval;
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen)) {
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to set TCP keepalive TCP_KEEPINTVL parameter\n");
}
optval = count;
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen)) {
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to set TCP keepalive TCP_KEEPCNT parameter\n");
}
@ -211,18 +233,20 @@ prepareAddress(const char* address, int port, struct sockaddr_in* sockaddr)
{
bool retVal = true;
memset((char *) sockaddr, 0, sizeof(struct sockaddr_in));
memset((char*)sockaddr, 0, sizeof(struct sockaddr_in));
if (address != NULL) {
if (address != NULL)
{
struct addrinfo addressHints;
struct addrinfo *lookupResult;
struct addrinfo* lookupResult;
int result;
memset(&addressHints, 0, sizeof(struct addrinfo));
addressHints.ai_family = AF_INET;
result = getaddrinfo(address, NULL, &addressHints, &lookupResult);
if (result != 0) {
if (result != 0)
{
if (DEBUG_SOCKET)
printf("SOCKET: getaddrinfo failed (code=%i)\n", result);
@ -260,7 +284,7 @@ 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));
setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
}
ServerSocket
@ -270,22 +294,25 @@ TcpServerSocket_create(const char* address, int port)
int fd;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
{
struct sockaddr_in serverAddress;
if (!prepareAddress(address, port, &serverAddress)) {
if (!prepareAddress(address, port, &serverAddress))
{
close(fd);
return NULL;
}
int optionReuseAddr = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optionReuseAddr, sizeof(int));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
int tcpUserTimeout = 10000;
int result = setsockopt(fd, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
int result = setsockopt(fd, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
if (result < 0) {
if (result < 0)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to set TCP_USER_TIMEOUT\n");
}
@ -293,16 +320,18 @@ TcpServerSocket_create(const char* address, int port)
#warning "TCP_USER_TIMEOUT not supported by linux kernel"
#endif
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket));
if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) >= 0)
{
serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd;
serverSocket->backLog = 2;
setSocketNonBlocking((Socket) serverSocket);
setSocketNonBlocking((Socket)serverSocket);
}
else {
else
{
close(fd);
return NULL ;
return NULL;
}
}
@ -312,7 +341,8 @@ TcpServerSocket_create(const char* address, int port)
void
ServerSocket_listen(ServerSocket self)
{
if (listen(self->fd, self->backLog) == -1) {
if (listen(self->fd, self->backLog) == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: listen failed (errno: %i)\n", errno);
}
@ -326,19 +356,22 @@ ServerSocket_accept(ServerSocket self)
Socket conSocket = NULL;
fd = accept(self->fd, NULL, NULL );
fd = accept(self->fd, NULL, NULL);
if (fd >= 0) {
conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (fd >= 0)
{
conSocket = (Socket)GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (conSocket) {
if (conSocket)
{
conSocket->fd = fd;
setSocketNonBlocking(conSocket);
activateTcpNoDelay(conSocket);
}
else {
else
{
/* out of memory */
close(fd);
@ -346,7 +379,8 @@ ServerSocket_accept(ServerSocket self)
printf("SOCKET: out of memory\n");
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: accept failed (errno=%i)\n", errno);
}
@ -363,7 +397,8 @@ ServerSocket_setBacklog(ServerSocket self, int backlog)
static void
closeAndShutdownSocket(int socketFd)
{
if (socketFd != -1) {
if (socketFd != -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: call shutdown for %i!\n", socketFd);
@ -371,14 +406,16 @@ closeAndShutdownSocket(int socketFd)
/* shutdown is required to unblock read or accept in another thread! */
int result = shutdown(socketFd, SHUT_RDWR);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: shutdown error: %i\n", errno);
}
result = close(socketFd);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: close error: %i\n", errno);
}
@ -406,24 +443,28 @@ TcpSocket_create()
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (Socket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->connectTimeout = 5000;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
int tcpUserTimeout = 10000;
int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to set TCP_USER_TIMEOUT (errno=%i)\n", errno);
}
#endif
}
else {
else
{
/* out of memory */
close(sock);
@ -431,7 +472,8 @@ TcpSocket_create()
printf("SOCKET: out of memory\n");
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create socket (errno=%i)\n", errno);
}
@ -455,7 +497,8 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind TCP socket (errno=%i)\n", errno);
@ -463,7 +506,7 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
self->fd = -1;
return false;
}
}
return true;
}
@ -479,18 +522,17 @@ Socket_connectAsync(Socket self, const char* address, int port)
if (!prepareAddress(address, port, &serverAddress))
return false;
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
activateTcpNoDelay(self);
fcntl(self->fd, F_SETFL, O_NONBLOCK);
if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
if (connect(self->fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0)
{
if (errno != EINPROGRESS) {
if (close(self->fd) == -1) {
if (errno != EINPROGRESS)
{
if (close(self->fd) == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to close socket (errno: %i)\n", errno);
}
@ -506,24 +548,23 @@ Socket_connectAsync(Socket self, const char* address, int port)
SocketState
Socket_checkAsyncConnectState(Socket self)
{
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
struct pollfd fds[1];
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
fds[0].fd = self->fd;
fds[0].events = POLLOUT;
int selectVal = select(self->fd + 1, NULL, &fdSet , NULL, &timeout);
int result = poll(fds, 1, 0);
if (selectVal == 1) {
if (result == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return SOCKET_STATE_CONNECTED;
@ -531,10 +572,12 @@ Socket_checkAsyncConnectState(Socket self)
return SOCKET_STATE_FAILED;
}
else if (selectVal == 0) {
else if (result == 0)
{
return SOCKET_STATE_CONNECTING;
}
else {
else
{
return SOCKET_STATE_FAILED;
}
}
@ -545,29 +588,30 @@ Socket_connect(Socket self, const char* address, int port)
if (Socket_connectAsync(self, address, port) == false)
return false;
struct timeval timeout;
timeout.tv_sec = self->connectTimeout / 1000;
timeout.tv_usec = (self->connectTimeout % 1000) * 1000;
struct pollfd fds[1];
fds[0].fd = self->fd;
fds[0].events = POLLOUT;
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
int result = poll(fds, 1, self->connectTimeout);
if (select(self->fd + 1, NULL, &fdSet , NULL, &timeout) == 1) {
if (result == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return true;
}
}
close (self->fd);
close(self->fd);
self->fd = -1;
return false;
@ -581,22 +625,24 @@ convertAddressToStr(struct sockaddr_storage* addr)
bool isIPv6;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) addr;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) addr;
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9);
char* clientConnection = (char*)GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
sprintf(clientConnection, "[%s]:%i", addrString, port);
@ -612,7 +658,8 @@ Socket_getPeerAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getpeername(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -625,7 +672,8 @@ Socket_getLocalAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getsockname(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getsockname(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -637,28 +685,37 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
{
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
getpeername(self->fd, (struct sockaddr*) &addr, &addrLen);
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == -1)
{
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: getpeername -> errno: %i\n", errno);
return NULL;
}
char addrString[INET6_ADDRSTRLEN + 7];
int port;
bool isIPv6;
if (addr.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr;
if (addr.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr;
else if (addr.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
if (isIPv6)
sprintf(peerAddressString, "[%s]:%i", addrString, port);
@ -679,22 +736,24 @@ Socket_read(Socket self, uint8_t* buf, int size)
if (read_bytes == 0)
return -1;
if (read_bytes == -1) {
if (read_bytes == -1)
{
int error = errno;
switch (error) {
switch (error)
{
case EAGAIN:
return 0;
case EBADF:
return -1;
case EAGAIN:
return 0;
case EBADF:
return -1;
default:
default:
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: recv returned error (errno=%i)\n", error);
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: recv returned error (errno=%i)\n", error);
return -1;
return -1;
}
}
@ -710,11 +769,14 @@ Socket_write(Socket self, uint8_t* buf, int size)
/* MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket */
int retVal = send(self->fd, buf, size, MSG_NOSIGNAL | MSG_DONTWAIT);
if (retVal == -1) {
if (errno == EAGAIN) {
if (retVal == -1)
{
if (errno == EAGAIN)
{
return 0;
}
else {
else
{
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: send returned error (errno=%i)\n", errno);
}
@ -744,21 +806,25 @@ UdpSocket_createUsingNamespace(int namespace)
int sock = socket(namespace, SOCK_DGRAM, IPPROTO_UDP);
if (sock != -1) {
self = (UdpSocket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (UdpSocket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->namespace = namespace;
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to allocate memory\n");
close(sock);
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create UDP socket (errno=%i)\n", errno);
}
@ -781,36 +847,42 @@ UdpSocket_createIpV6()
bool
UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
{
if (self->namespace == AF_INET) {
if (self->namespace == AF_INET)
{
struct ip_mreq mreq;
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr))) {
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr)))
{
printf("SOCKET: Invalid IPv4 multicast address\n");
return false;
}
else {
else
{
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", errno);
return false;
}
}
return true;
}
else if (self->namespace == AF_INET6) {
else if (self->namespace == AF_INET6)
{
struct ipv6_mreq mreq;
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1) {
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
mreq.ipv6mr_interface = 0;
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
@ -824,16 +896,20 @@ UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
bool
UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
{
if (self->namespace == AF_INET) {
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
if (self->namespace == AF_INET)
{
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", errno);
return false;
}
return true;
}
else if (self->namespace == AF_INET6) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
else if (self->namespace == AF_INET6)
{
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", errno);
return false;
}
@ -847,10 +923,11 @@ UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
bool
UdpSocket_bind(UdpSocket self, const char* address, int port)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in localAddress;
if (!prepareAddress(address, port, &localAddress)) {
if (!prepareAddress(address, port, &localAddress))
{
close(self->fd);
self->fd = 0;
return false;
@ -858,7 +935,8 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind UDP socket (errno=%i)\n", errno);
@ -874,10 +952,11 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
bool
UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in remoteAddress;
if (!prepareAddress(address, port, &remoteAddress)) {
if (!prepareAddress(address, port, &remoteAddress))
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address);
@ -887,14 +966,17 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int result = sendto(self->fd, msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress));
if (result == msgSize) {
if (result == msgSize)
{
return true;
}
else if (result == -1) {
else if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (errno=%i)\n", errno);
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (insufficient data sent)\n");
}
@ -905,31 +987,35 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int
UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_storage remoteAddress;
memset(&remoteAddress, 0, sizeof(struct sockaddr_storage));
socklen_t structSize = sizeof(struct sockaddr_storage);
int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno);
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save