diff options
Diffstat (limited to 'src/3rdparty/open62541/open62541.c')
-rw-r--r-- | src/3rdparty/open62541/open62541.c | 59419 |
1 files changed, 33978 insertions, 25441 deletions
diff --git a/src/3rdparty/open62541/open62541.c b/src/3rdparty/open62541/open62541.c index 9d508ae..c3692d3 100644 --- a/src/3rdparty/open62541/open62541.c +++ b/src/3rdparty/open62541/open62541.c @@ -1,10 +1,10 @@ /* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES * visit http://open62541.org/ for information about this software - * Git-Revision: v1.1.2-8-ge941fc23 + * Git-Revision: v1.3.3 */ /* - * Copyright (C) 2014-2018 the contributors as stated in the AUTHORS file + * Copyright (C) 2014-2021 the contributors as stated in the AUTHORS file * * This file is part of open62541. open62541 is free software: you can * redistribute it and/or modify it under the terms of the Mozilla Public @@ -27,7 +27,7 @@ #include "open62541.h" -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/open62541_queue.h" ***********************************/ +/**** amalgamated original file "/deps/open62541_queue.h" ****/ /* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ @@ -154,9 +154,9 @@ struct { \ /* * Singly-linked List functions. */ -#define SLIST_INIT(head) { \ +#define SLIST_INIT(head) do { \ SLIST_FIRST(head) = SLIST_END(head); \ -} +} while(0) #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ @@ -675,7 +675,7 @@ struct { \ } while (0) -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/pcg_basic.h" ***********************************/ +/**** amalgamated original file "/deps/pcg_basic.h" ****/ /* * PCG Random Number Generation for C. @@ -722,7 +722,7 @@ uint32_t pcg32_random_r(pcg32_random_t* rng); #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/libc_time.h" ***********************************/ +/**** amalgamated original file "/deps/libc_time.h" ****/ struct mytm { @@ -738,7 +738,7 @@ int __secs_to_tm(long long t, struct mytm *tm); long long __tm_to_secs(const struct mytm *tm); -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/base64.h" ***********************************/ +/**** amalgamated original file "/deps/base64.h" ****/ #ifndef UA_BASE64_H_ #define UA_BASE64_H_ @@ -772,7 +772,81 @@ _UA_END_DECLS #endif /* UA_BASE64_H_ */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_util_internal.h" ***********************************/ +/**** amalgamated original file "/src/ua_types_encoding_binary.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2015 (c) Sten Grüner + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + + +_UA_BEGIN_DECLS + +typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos, + const UA_Byte **bufEnd); + +/* Encodes the scalar value described by type in the binary encoding. Encoding + * is thread-safe if thread-local variables are enabled. Encoding is also + * reentrant and can be safely called from signal handlers or interrupts. + * + * @param src The value. Must not be NULL. + * @param type The value type. Must not be NULL. + * @param bufPos Points to a pointer to the current position in the encoding + * buffer. Must not be NULL. The pointer is advanced by the number of + * encoded bytes, or, if the buffer is exchanged, to the position in the + * new buffer. + * @param bufEnd Points to a pointer to the end of the encoding buffer (encoding + * always stops before *buf_end). Must not be NULL. The pointer is + * changed when the buffer is exchanged. + * @param exchangeCallback Called when the end of the buffer is reached. This is + used to send out a message chunk before continuing with the encoding. + Is ignored if NULL. + * @param exchangeHandle Custom data passed into the exchangeCallback. + * @return Returns a statuscode whether encoding succeeded. */ +UA_StatusCode +UA_encodeBinaryInternal(const void *src, const UA_DataType *type, + UA_Byte **bufPos, const UA_Byte **bufEnd, + UA_exchangeEncodeBuffer exchangeCallback, + void *exchangeHandle) + UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +/* Decodes a scalar value described by type from binary encoding. Decoding + * is thread-safe if thread-local variables are enabled. Decoding is also + * reentrant and can be safely called from signal handlers or interrupts. + * + * @param src The buffer with the binary encoded value. Must not be NULL. + * @param offset The current position in the buffer. Must not be NULL. The value + * is advanced as decoding progresses. + * @param dst The target value. Must not be NULL. The target is assumed to have + * size type->memSize. The value is reset to zero before decoding. If + * decoding fails, members are deleted and the value is reset (zeroed) + * again. + * @param type The value type. Must not be NULL. + * @param customTypesSize The number of non-standard datatypes contained in the + * customTypes array. + * @param customTypes An array of non-standard datatypes (not included in + * UA_TYPES). Can be NULL if customTypesSize is zero. + * @return Returns a statuscode whether decoding succeeded. */ +UA_StatusCode +UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset, + void *dst, const UA_DataType *type, + const UA_DataTypeArray *customTypes) + UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +const UA_DataType * +UA_findDataTypeByBinary(const UA_NodeId *typeId); + +_UA_END_DECLS + + +/**** amalgamated original file "/src/ua_util_internal.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -785,23 +859,68 @@ _UA_END_DECLS * Copyright 2015 (c) Chris Iatrou * Copyright 2015-2016 (c) Oleksiy Vasylyev * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes) */ #define UA_INTERNAL + _UA_BEGIN_DECLS /* Macro-Expand for MSVC workarounds */ #define UA_MACRO_EXPAND(x) x /* Print a NodeId in logs */ -#define UA_LOG_NODEID_WRAP(NODEID, LOG) { \ - UA_String nodeIdStr = UA_STRING_NULL; \ - UA_NodeId_print(NODEID, &nodeIdStr); \ - LOG; \ - UA_String_clear(&nodeIdStr); \ -} +#define UA_LOG_NODEID_INTERNAL(NODEID, LOG) \ + do { \ + UA_String nodeIdStr = UA_STRING_NULL; \ + UA_NodeId_print(NODEID, &nodeIdStr); \ + LOG; \ + UA_String_clear(&nodeIdStr); \ + } while(0) + +#if UA_LOGLEVEL <= 100 +# define UA_LOG_NODEID_TRACE(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_TRACE(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 200 +# define UA_LOG_NODEID_DEBUG(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_DEBUG(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 300 +# define UA_LOG_NODEID_INFO(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_INFO(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 400 +# define UA_LOG_NODEID_WARNING(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_WARNING(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 500 +# define UA_LOG_NODEID_ERROR(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_ERROR(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 600 +# define UA_LOG_NODEID_FATAL(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_FATAL(NODEID, LOG) +#endif /* Short names for integer. These are not exposed on the public API, since many * user-applications make the same definitions in their headers. */ @@ -816,9 +935,122 @@ typedef UA_Int64 i64; typedef UA_StatusCode status; /** + * Error checking macros + */ + +static UA_INLINE UA_Boolean +isGood(UA_StatusCode code) { + return code == UA_STATUSCODE_GOOD; +} + +static UA_INLINE UA_Boolean +isNonNull(const void *ptr) { + return ptr != NULL; +} + +static UA_INLINE UA_Boolean +isTrue(uint8_t expr) { + return expr; +} + +#define UA_CHECK(A, EVAL_ON_ERROR) \ + do { \ + if(UA_UNLIKELY(!isTrue(A))) { \ + EVAL_ON_ERROR; \ + } \ + } while(0) + +#define UA_CHECK_STATUS(STATUSCODE, EVAL_ON_ERROR) \ + UA_CHECK(isGood(STATUSCODE), EVAL_ON_ERROR) + +#define UA_CHECK_MEM(STATUSCODE, EVAL_ON_ERROR) \ + UA_CHECK(isNonNull(STATUSCODE), EVAL_ON_ERROR) + +#ifdef UA_DEBUG_FILE_LINE_INFO +#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (%s:%d: statuscode: %s)", __VA_ARGS__, \ + __FILE__, __LINE__, UA_StatusCode_name(STATUSCODE)); \ + EVAL)) +#else +#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (statuscode: %s)", __VA_ARGS__, \ + UA_StatusCode_name(STATUSCODE)); \ + EVAL)) +#endif + +#define UA_CHECK_LOG(A, EVAL, LEVEL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(A, UA_STATUSCODE_BAD, EVAL, UA_LOG_##LEVEL, \ + LOGGER, CAT, __VA_ARGS__, "")) + +#define UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, LEVEL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isGood(STATUSCODE), STATUSCODE, \ + EVAL, UA_LOG_##LEVEL, LOGGER, CAT, \ + __VA_ARGS__, "")) + +#define UA_CHECK_MEM_LOG(PTR, EVAL, LEVEL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isNonNull(PTR), UA_STATUSCODE_BADOUTOFMEMORY, \ + EVAL, UA_LOG_##LEVEL, LOGGER, CAT, \ + __VA_ARGS__, "")) + +/** + * Check Macros + * Usage examples: + * + * void *data = malloc(...); + * UA_CHECK(data, return error); + * + * UA_StatusCode rv = some_func(...); + * UA_CHECK_STATUS(rv, return rv); + * + * UA_Logger *logger = &server->config.logger; + * rv = bar_func(...); + * UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SERVER, "msg & args %s", "arg"); + */ +#define UA_CHECK_FATAL(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_ERROR(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_WARN(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_INFO(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, INFO, LOGGER, CAT, __VA_ARGS__)) + +#define UA_CHECK_STATUS_FATAL(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_STATUS_ERROR(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_STATUS_WARN(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_STATUS_INFO(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, INFO, LOGGER, CAT, __VA_ARGS__)) + +#define UA_CHECK_MEM_FATAL(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_MEM_ERROR(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_MEM_WARN(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_MEM_INFO(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, INFO, LOGGER, CAT, __VA_ARGS__)) + +/** * Utility Functions * ----------------- */ +const UA_DataType * +UA_findDataTypeWithCustom(const UA_NodeId *typeId, + const UA_DataTypeArray *customTypes); + /* Get the number of optional fields contained in an structure type */ size_t UA_EXPORT getCountOfOptionalFields(const UA_DataType *type); @@ -924,3022 +1156,73 @@ typedef union { #endif } UA_Response; -_UA_END_DECLS - - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_types_encoding_binary.h" ***********************************/ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2015 (c) Sten Grüner - * Copyright 2014, 2017 (c) Florian Palm - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH - * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB - */ - - - -_UA_BEGIN_DECLS - -typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos, - const UA_Byte **bufEnd); - -/* Encodes the scalar value described by type in the binary encoding. Encoding - * is thread-safe if thread-local variables are enabled. Encoding is also - * reentrant and can be safely called from signal handlers or interrupts. - * - * @param src The value. Must not be NULL. - * @param type The value type. Must not be NULL. - * @param bufPos Points to a pointer to the current position in the encoding - * buffer. Must not be NULL. The pointer is advanced by the number of - * encoded bytes, or, if the buffer is exchanged, to the position in the - * new buffer. - * @param bufEnd Points to a pointer to the end of the encoding buffer (encoding - * always stops before *buf_end). Must not be NULL. The pointer is - * changed when the buffer is exchanged. - * @param exchangeCallback Called when the end of the buffer is reached. This is - used to send out a message chunk before continuing with the encoding. - Is ignored if NULL. - * @param exchangeHandle Custom data passed into the exchangeCallback. - * @return Returns a statuscode whether encoding succeeded. */ -UA_StatusCode -UA_encodeBinary(const void *src, const UA_DataType *type, - UA_Byte **bufPos, const UA_Byte **bufEnd, - UA_exchangeEncodeBuffer exchangeCallback, - void *exchangeHandle) UA_FUNC_ATTR_WARN_UNUSED_RESULT; - -/* Decodes a scalar value described by type from binary encoding. Decoding - * is thread-safe if thread-local variables are enabled. Decoding is also - * reentrant and can be safely called from signal handlers or interrupts. - * - * @param src The buffer with the binary encoded value. Must not be NULL. - * @param offset The current position in the buffer. Must not be NULL. The value - * is advanced as decoding progresses. - * @param dst The target value. Must not be NULL. The target is assumed to have - * size type->memSize. The value is reset to zero before decoding. If - * decoding fails, members are deleted and the value is reset (zeroed) - * again. - * @param type The value type. Must not be NULL. - * @param customTypesSize The number of non-standard datatypes contained in the - * customTypes array. - * @param customTypes An array of non-standard datatypes (not included in - * UA_TYPES). Can be NULL if customTypesSize is zero. - * @return Returns a statuscode whether decoding succeeded. */ -UA_StatusCode -UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, - const UA_DataType *type, const UA_DataTypeArray *customTypes) - UA_FUNC_ATTR_WARN_UNUSED_RESULT; +/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles + * ASCII strings, and not UTF8! */ +UA_Boolean UA_EXPORT +UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2); -/* Returns the number of bytes the value p takes in binary encoding. Returns - * zero if an error occurs. UA_calcSizeBinary is thread-safe and reentrant since - * it does not access global (thread-local) variables. */ -size_t -UA_calcSizeBinary(const void *p, const UA_DataType *type); +/********************/ +/* Encoding Helpers */ +/********************/ -const UA_DataType * -UA_findDataTypeByBinary(const UA_NodeId *typeId); +#define UA_ENCODING_HELPERS(TYPE, UPCASE_TYPE) \ + static UA_INLINE size_t \ + UA_##TYPE##_calcSizeBinary(const UA_##TYPE *src) { \ + return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE]); \ + } \ + static UA_INLINE UA_StatusCode \ + UA_##TYPE##_encodeBinary(const UA_##TYPE *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { \ + return UA_encodeBinaryInternal(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE], \ + bufPos, &bufEnd, NULL, NULL); \ + } \ + static UA_INLINE UA_StatusCode \ + UA_##TYPE##_decodeBinary(const UA_ByteString *src, size_t *offset, UA_##TYPE *dst) { \ + return UA_decodeBinaryInternal(src, offset, dst, \ + &UA_TYPES[UA_TYPES_##UPCASE_TYPE], NULL); \ + } + +UA_ENCODING_HELPERS(Boolean, BOOLEAN) +UA_ENCODING_HELPERS(SByte, SBYTE) +UA_ENCODING_HELPERS(Byte, BYTE) +UA_ENCODING_HELPERS(Int16, INT16) +UA_ENCODING_HELPERS(UInt16, UINT16) +UA_ENCODING_HELPERS(Int32, INT32) +UA_ENCODING_HELPERS(UInt32, UINT32) +UA_ENCODING_HELPERS(Int64, INT64) +UA_ENCODING_HELPERS(UInt64, UINT64) +UA_ENCODING_HELPERS(Float, FLOAT) +UA_ENCODING_HELPERS(Double, DOUBLE) +UA_ENCODING_HELPERS(String, STRING) +UA_ENCODING_HELPERS(DateTime, DATETIME) +UA_ENCODING_HELPERS(Guid, GUID) +UA_ENCODING_HELPERS(ByteString, BYTESTRING) +UA_ENCODING_HELPERS(XmlElement, XMLELEMENT) +UA_ENCODING_HELPERS(NodeId, NODEID) +UA_ENCODING_HELPERS(ExpandedNodeId, EXPANDEDNODEID) +UA_ENCODING_HELPERS(StatusCode, STATUSCODE) +UA_ENCODING_HELPERS(QualifiedName, QUALIFIEDNAME) +UA_ENCODING_HELPERS(LocalizedText, LOCALIZEDTEXT) +UA_ENCODING_HELPERS(ExtensionObject, EXTENSIONOBJECT) +UA_ENCODING_HELPERS(DataValue, DATAVALUE) +UA_ENCODING_HELPERS(Variant, VARIANT) +UA_ENCODING_HELPERS(DiagnosticInfo, DIAGNOSTICINFO) _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/types_generated_encoding_binary.h" ***********************************/ +/**** amalgamated original file "/build/src_generated/open62541/transport_generated.h" ****/ -/* Generated from Opc.Ua.Types.bsd with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_datatypes.py - * on host mintaka by user pdie at 2021-06-21 11:34:37 */ +/********************************** + * Autogenerated -- do not modify * + **********************************/ #ifdef UA_ENABLE_AMALGAMATION #else -#endif - - - -/* Boolean */ -static UA_INLINE size_t -UA_Boolean_calcSizeBinary(const UA_Boolean *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BOOLEAN]); -} -static UA_INLINE UA_StatusCode -UA_Boolean_encodeBinary(const UA_Boolean *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BOOLEAN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Boolean_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Boolean *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BOOLEAN], NULL); -} - -/* SByte */ -static UA_INLINE size_t -UA_SByte_calcSizeBinary(const UA_SByte *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SBYTE]); -} -static UA_INLINE UA_StatusCode -UA_SByte_encodeBinary(const UA_SByte *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SBYTE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SByte_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SByte *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SBYTE], NULL); -} - -/* Byte */ -static UA_INLINE size_t -UA_Byte_calcSizeBinary(const UA_Byte *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BYTE]); -} -static UA_INLINE UA_StatusCode -UA_Byte_encodeBinary(const UA_Byte *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BYTE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Byte_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Byte *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BYTE], NULL); -} - -/* Int16 */ -static UA_INLINE size_t -UA_Int16_calcSizeBinary(const UA_Int16 *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_INT16]); -} -static UA_INLINE UA_StatusCode -UA_Int16_encodeBinary(const UA_Int16 *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_INT16], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Int16_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Int16 *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_INT16], NULL); -} - -/* UInt16 */ -static UA_INLINE size_t -UA_UInt16_calcSizeBinary(const UA_UInt16 *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UINT16]); -} -static UA_INLINE UA_StatusCode -UA_UInt16_encodeBinary(const UA_UInt16 *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UINT16], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UInt16_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UInt16 *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UINT16], NULL); -} - -/* Int32 */ -static UA_INLINE size_t -UA_Int32_calcSizeBinary(const UA_Int32 *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_INT32]); -} -static UA_INLINE UA_StatusCode -UA_Int32_encodeBinary(const UA_Int32 *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_INT32], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Int32_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Int32 *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_INT32], NULL); -} - -/* UInt32 */ -static UA_INLINE size_t -UA_UInt32_calcSizeBinary(const UA_UInt32 *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UINT32]); -} -static UA_INLINE UA_StatusCode -UA_UInt32_encodeBinary(const UA_UInt32 *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UINT32], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UInt32_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UInt32 *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UINT32], NULL); -} - -/* Int64 */ -static UA_INLINE size_t -UA_Int64_calcSizeBinary(const UA_Int64 *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_INT64]); -} -static UA_INLINE UA_StatusCode -UA_Int64_encodeBinary(const UA_Int64 *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_INT64], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Int64_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Int64 *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_INT64], NULL); -} - -/* UInt64 */ -static UA_INLINE size_t -UA_UInt64_calcSizeBinary(const UA_UInt64 *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UINT64]); -} -static UA_INLINE UA_StatusCode -UA_UInt64_encodeBinary(const UA_UInt64 *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UINT64], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UInt64_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UInt64 *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UINT64], NULL); -} - -/* Float */ -static UA_INLINE size_t -UA_Float_calcSizeBinary(const UA_Float *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_FLOAT]); -} -static UA_INLINE UA_StatusCode -UA_Float_encodeBinary(const UA_Float *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FLOAT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Float_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Float *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FLOAT], NULL); -} - -/* Double */ -static UA_INLINE size_t -UA_Double_calcSizeBinary(const UA_Double *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DOUBLE]); -} -static UA_INLINE UA_StatusCode -UA_Double_encodeBinary(const UA_Double *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DOUBLE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Double_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Double *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DOUBLE], NULL); -} - -/* String */ -static UA_INLINE size_t -UA_String_calcSizeBinary(const UA_String *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_STRING]); -} -static UA_INLINE UA_StatusCode -UA_String_encodeBinary(const UA_String *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_STRING], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_String_decodeBinary(const UA_ByteString *src, size_t *offset, UA_String *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_STRING], NULL); -} - -/* DateTime */ -static UA_INLINE size_t -UA_DateTime_calcSizeBinary(const UA_DateTime *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DATETIME]); -} -static UA_INLINE UA_StatusCode -UA_DateTime_encodeBinary(const UA_DateTime *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DATETIME], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DateTime_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DateTime *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DATETIME], NULL); -} - -/* Guid */ -static UA_INLINE size_t -UA_Guid_calcSizeBinary(const UA_Guid *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_GUID]); -} -static UA_INLINE UA_StatusCode -UA_Guid_encodeBinary(const UA_Guid *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_GUID], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Guid_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Guid *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_GUID], NULL); -} - -/* ByteString */ -static UA_INLINE size_t -UA_ByteString_calcSizeBinary(const UA_ByteString *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BYTESTRING]); -} -static UA_INLINE UA_StatusCode -UA_ByteString_encodeBinary(const UA_ByteString *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BYTESTRING], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ByteString_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ByteString *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BYTESTRING], NULL); -} - -/* XmlElement */ -static UA_INLINE size_t -UA_XmlElement_calcSizeBinary(const UA_XmlElement *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_XMLELEMENT]); -} -static UA_INLINE UA_StatusCode -UA_XmlElement_encodeBinary(const UA_XmlElement *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_XMLELEMENT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_XmlElement_decodeBinary(const UA_ByteString *src, size_t *offset, UA_XmlElement *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_XMLELEMENT], NULL); -} - -/* NodeId */ -static UA_INLINE size_t -UA_NodeId_calcSizeBinary(const UA_NodeId *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_NODEID]); -} -static UA_INLINE UA_StatusCode -UA_NodeId_encodeBinary(const UA_NodeId *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NODEID], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_NodeId_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NodeId *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NODEID], NULL); -} - -/* ExpandedNodeId */ -static UA_INLINE size_t -UA_ExpandedNodeId_calcSizeBinary(const UA_ExpandedNodeId *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); -} -static UA_INLINE UA_StatusCode -UA_ExpandedNodeId_encodeBinary(const UA_ExpandedNodeId *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EXPANDEDNODEID], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ExpandedNodeId_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ExpandedNodeId *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EXPANDEDNODEID], NULL); -} - -/* StatusCode */ -static UA_INLINE size_t -UA_StatusCode_calcSizeBinary(const UA_StatusCode *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_STATUSCODE]); -} -static UA_INLINE UA_StatusCode -UA_StatusCode_encodeBinary(const UA_StatusCode *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_STATUSCODE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_StatusCode_decodeBinary(const UA_ByteString *src, size_t *offset, UA_StatusCode *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_STATUSCODE], NULL); -} - -/* QualifiedName */ -static UA_INLINE size_t -UA_QualifiedName_calcSizeBinary(const UA_QualifiedName *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); -} -static UA_INLINE UA_StatusCode -UA_QualifiedName_encodeBinary(const UA_QualifiedName *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUALIFIEDNAME], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_QualifiedName_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QualifiedName *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUALIFIEDNAME], NULL); -} - -/* LocalizedText */ -static UA_INLINE size_t -UA_LocalizedText_calcSizeBinary(const UA_LocalizedText *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); -} -static UA_INLINE UA_StatusCode -UA_LocalizedText_encodeBinary(const UA_LocalizedText *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_LocalizedText_decodeBinary(const UA_ByteString *src, size_t *offset, UA_LocalizedText *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], NULL); -} - -/* ExtensionObject */ -static UA_INLINE size_t -UA_ExtensionObject_calcSizeBinary(const UA_ExtensionObject *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); -} -static UA_INLINE UA_StatusCode -UA_ExtensionObject_encodeBinary(const UA_ExtensionObject *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ExtensionObject_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ExtensionObject *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], NULL); -} - -/* DataValue */ -static UA_INLINE size_t -UA_DataValue_calcSizeBinary(const UA_DataValue *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DATAVALUE]); -} -static UA_INLINE UA_StatusCode -UA_DataValue_encodeBinary(const UA_DataValue *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DATAVALUE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DataValue_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataValue *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DATAVALUE], NULL); -} - -/* Variant */ -static UA_INLINE size_t -UA_Variant_calcSizeBinary(const UA_Variant *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_VARIANT]); -} -static UA_INLINE UA_StatusCode -UA_Variant_encodeBinary(const UA_Variant *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_VARIANT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Variant_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Variant *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_VARIANT], NULL); -} - -/* DiagnosticInfo */ -static UA_INLINE size_t -UA_DiagnosticInfo_calcSizeBinary(const UA_DiagnosticInfo *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO]); -} -static UA_INLINE UA_StatusCode -UA_DiagnosticInfo_encodeBinary(const UA_DiagnosticInfo *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DiagnosticInfo_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DiagnosticInfo *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], NULL); -} - -/* NodeClass */ -static UA_INLINE size_t -UA_NodeClass_calcSizeBinary(const UA_NodeClass *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_NODECLASS]); -} -static UA_INLINE UA_StatusCode -UA_NodeClass_encodeBinary(const UA_NodeClass *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NODECLASS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_NodeClass_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NodeClass *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NODECLASS], NULL); -} - -/* StructureType */ -static UA_INLINE size_t -UA_StructureType_calcSizeBinary(const UA_StructureType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_STRUCTURETYPE]); -} -static UA_INLINE UA_StatusCode -UA_StructureType_encodeBinary(const UA_StructureType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_STRUCTURETYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_StructureType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_StructureType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_STRUCTURETYPE], NULL); -} - -/* StructureField */ -static UA_INLINE size_t -UA_StructureField_calcSizeBinary(const UA_StructureField *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_STRUCTUREFIELD]); -} -static UA_INLINE UA_StatusCode -UA_StructureField_encodeBinary(const UA_StructureField *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_STRUCTUREFIELD], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_StructureField_decodeBinary(const UA_ByteString *src, size_t *offset, UA_StructureField *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_STRUCTUREFIELD], NULL); -} - -/* StructureDefinition */ -static UA_INLINE size_t -UA_StructureDefinition_calcSizeBinary(const UA_StructureDefinition *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]); -} -static UA_INLINE UA_StatusCode -UA_StructureDefinition_encodeBinary(const UA_StructureDefinition *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_StructureDefinition_decodeBinary(const UA_ByteString *src, size_t *offset, UA_StructureDefinition *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION], NULL); -} - -/* Argument */ -static UA_INLINE size_t -UA_Argument_calcSizeBinary(const UA_Argument *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ARGUMENT]); -} -static UA_INLINE UA_StatusCode -UA_Argument_encodeBinary(const UA_Argument *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ARGUMENT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Argument_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Argument *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ARGUMENT], NULL); -} - -/* EnumValueType */ -static UA_INLINE size_t -UA_EnumValueType_calcSizeBinary(const UA_EnumValueType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); -} -static UA_INLINE UA_StatusCode -UA_EnumValueType_encodeBinary(const UA_EnumValueType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ENUMVALUETYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EnumValueType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EnumValueType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ENUMVALUETYPE], NULL); -} - -/* EnumField */ -static UA_INLINE size_t -UA_EnumField_calcSizeBinary(const UA_EnumField *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ENUMFIELD]); -} -static UA_INLINE UA_StatusCode -UA_EnumField_encodeBinary(const UA_EnumField *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ENUMFIELD], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EnumField_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EnumField *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ENUMFIELD], NULL); -} - -/* Duration */ -static UA_INLINE size_t -UA_Duration_calcSizeBinary(const UA_Duration *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DURATION]); -} -static UA_INLINE UA_StatusCode -UA_Duration_encodeBinary(const UA_Duration *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DURATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Duration_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Duration *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DURATION], NULL); -} - -/* UtcTime */ -static UA_INLINE size_t -UA_UtcTime_calcSizeBinary(const UA_UtcTime *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UTCTIME]); -} -static UA_INLINE UA_StatusCode -UA_UtcTime_encodeBinary(const UA_UtcTime *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UTCTIME], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UtcTime_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UtcTime *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UTCTIME], NULL); -} - -/* LocaleId */ -static UA_INLINE size_t -UA_LocaleId_calcSizeBinary(const UA_LocaleId *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_LOCALEID]); -} -static UA_INLINE UA_StatusCode -UA_LocaleId_encodeBinary(const UA_LocaleId *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_LOCALEID], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_LocaleId_decodeBinary(const UA_ByteString *src, size_t *offset, UA_LocaleId *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_LOCALEID], NULL); -} - -/* TimeZoneDataType */ -static UA_INLINE size_t -UA_TimeZoneDataType_calcSizeBinary(const UA_TimeZoneDataType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_TIMEZONEDATATYPE]); -} -static UA_INLINE UA_StatusCode -UA_TimeZoneDataType_encodeBinary(const UA_TimeZoneDataType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_TIMEZONEDATATYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TimeZoneDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TimeZoneDataType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_TIMEZONEDATATYPE], NULL); -} - -/* ApplicationType */ -static UA_INLINE size_t -UA_ApplicationType_calcSizeBinary(const UA_ApplicationType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_APPLICATIONTYPE]); -} -static UA_INLINE UA_StatusCode -UA_ApplicationType_encodeBinary(const UA_ApplicationType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_APPLICATIONTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ApplicationType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ApplicationType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_APPLICATIONTYPE], NULL); -} - -/* ApplicationDescription */ -static UA_INLINE size_t -UA_ApplicationDescription_calcSizeBinary(const UA_ApplicationDescription *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]); -} -static UA_INLINE UA_StatusCode -UA_ApplicationDescription_encodeBinary(const UA_ApplicationDescription *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ApplicationDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ApplicationDescription *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], NULL); -} - -/* RequestHeader */ -static UA_INLINE size_t -UA_RequestHeader_calcSizeBinary(const UA_RequestHeader *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REQUESTHEADER]); -} -static UA_INLINE UA_StatusCode -UA_RequestHeader_encodeBinary(const UA_RequestHeader *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REQUESTHEADER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RequestHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RequestHeader *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REQUESTHEADER], NULL); -} - -/* ResponseHeader */ -static UA_INLINE size_t -UA_ResponseHeader_calcSizeBinary(const UA_ResponseHeader *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_RESPONSEHEADER]); -} -static UA_INLINE UA_StatusCode -UA_ResponseHeader_encodeBinary(const UA_ResponseHeader *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_RESPONSEHEADER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ResponseHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ResponseHeader *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_RESPONSEHEADER], NULL); -} - -/* ServiceFault */ -static UA_INLINE size_t -UA_ServiceFault_calcSizeBinary(const UA_ServiceFault *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SERVICEFAULT]); -} -static UA_INLINE UA_StatusCode -UA_ServiceFault_encodeBinary(const UA_ServiceFault *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SERVICEFAULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ServiceFault_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ServiceFault *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SERVICEFAULT], NULL); -} - -/* FindServersRequest */ -static UA_INLINE size_t -UA_FindServersRequest_calcSizeBinary(const UA_FindServersRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_FindServersRequest_encodeBinary(const UA_FindServersRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_FindServersRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_FindServersRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST], NULL); -} - -/* FindServersResponse */ -static UA_INLINE size_t -UA_FindServersResponse_calcSizeBinary(const UA_FindServersResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_FindServersResponse_encodeBinary(const UA_FindServersResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_FindServersResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_FindServersResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE], NULL); -} - -/* MessageSecurityMode */ -static UA_INLINE size_t -UA_MessageSecurityMode_calcSizeBinary(const UA_MessageSecurityMode *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE]); -} -static UA_INLINE UA_StatusCode -UA_MessageSecurityMode_encodeBinary(const UA_MessageSecurityMode *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MessageSecurityMode_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MessageSecurityMode *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], NULL); -} - -/* UserTokenType */ -static UA_INLINE size_t -UA_UserTokenType_calcSizeBinary(const UA_UserTokenType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_USERTOKENTYPE]); -} -static UA_INLINE UA_StatusCode -UA_UserTokenType_encodeBinary(const UA_UserTokenType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_USERTOKENTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UserTokenType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UserTokenType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_USERTOKENTYPE], NULL); -} - -/* UserTokenPolicy */ -static UA_INLINE size_t -UA_UserTokenPolicy_calcSizeBinary(const UA_UserTokenPolicy *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); -} -static UA_INLINE UA_StatusCode -UA_UserTokenPolicy_encodeBinary(const UA_UserTokenPolicy *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_USERTOKENPOLICY], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UserTokenPolicy_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UserTokenPolicy *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_USERTOKENPOLICY], NULL); -} - -/* EndpointDescription */ -static UA_INLINE size_t -UA_EndpointDescription_calcSizeBinary(const UA_EndpointDescription *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); -} -static UA_INLINE UA_StatusCode -UA_EndpointDescription_encodeBinary(const UA_EndpointDescription *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EndpointDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EndpointDescription *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], NULL); -} - -/* GetEndpointsRequest */ -static UA_INLINE size_t -UA_GetEndpointsRequest_calcSizeBinary(const UA_GetEndpointsRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_GetEndpointsRequest_encodeBinary(const UA_GetEndpointsRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_GetEndpointsRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_GetEndpointsRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], NULL); -} - -/* GetEndpointsResponse */ -static UA_INLINE size_t -UA_GetEndpointsResponse_calcSizeBinary(const UA_GetEndpointsResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_GetEndpointsResponse_encodeBinary(const UA_GetEndpointsResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_GetEndpointsResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_GetEndpointsResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE], NULL); -} - -/* SecurityTokenRequestType */ -static UA_INLINE size_t -UA_SecurityTokenRequestType_calcSizeBinary(const UA_SecurityTokenRequestType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE]); -} -static UA_INLINE UA_StatusCode -UA_SecurityTokenRequestType_encodeBinary(const UA_SecurityTokenRequestType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SecurityTokenRequestType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SecurityTokenRequestType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE], NULL); -} - -/* ChannelSecurityToken */ -static UA_INLINE size_t -UA_ChannelSecurityToken_calcSizeBinary(const UA_ChannelSecurityToken *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN]); -} -static UA_INLINE UA_StatusCode -UA_ChannelSecurityToken_encodeBinary(const UA_ChannelSecurityToken *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ChannelSecurityToken_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ChannelSecurityToken *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN], NULL); -} - -/* OpenSecureChannelRequest */ -static UA_INLINE size_t -UA_OpenSecureChannelRequest_calcSizeBinary(const UA_OpenSecureChannelRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_OpenSecureChannelRequest_encodeBinary(const UA_OpenSecureChannelRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_OpenSecureChannelRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_OpenSecureChannelRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST], NULL); -} - -/* OpenSecureChannelResponse */ -static UA_INLINE size_t -UA_OpenSecureChannelResponse_calcSizeBinary(const UA_OpenSecureChannelResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_OpenSecureChannelResponse_encodeBinary(const UA_OpenSecureChannelResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_OpenSecureChannelResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_OpenSecureChannelResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], NULL); -} - -/* CloseSecureChannelRequest */ -static UA_INLINE size_t -UA_CloseSecureChannelRequest_calcSizeBinary(const UA_CloseSecureChannelRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CloseSecureChannelRequest_encodeBinary(const UA_CloseSecureChannelRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CloseSecureChannelRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CloseSecureChannelRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], NULL); -} - -/* CloseSecureChannelResponse */ -static UA_INLINE size_t -UA_CloseSecureChannelResponse_calcSizeBinary(const UA_CloseSecureChannelResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_CloseSecureChannelResponse_encodeBinary(const UA_CloseSecureChannelResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CloseSecureChannelResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CloseSecureChannelResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELRESPONSE], NULL); -} - -/* SignedSoftwareCertificate */ -static UA_INLINE size_t -UA_SignedSoftwareCertificate_calcSizeBinary(const UA_SignedSoftwareCertificate *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE]); -} -static UA_INLINE UA_StatusCode -UA_SignedSoftwareCertificate_encodeBinary(const UA_SignedSoftwareCertificate *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SignedSoftwareCertificate_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SignedSoftwareCertificate *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], NULL); -} - -/* SignatureData */ -static UA_INLINE size_t -UA_SignatureData_calcSizeBinary(const UA_SignatureData *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SIGNATUREDATA]); -} -static UA_INLINE UA_StatusCode -UA_SignatureData_encodeBinary(const UA_SignatureData *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SIGNATUREDATA], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SignatureData_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SignatureData *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SIGNATUREDATA], NULL); -} - -/* CreateSessionRequest */ -static UA_INLINE size_t -UA_CreateSessionRequest_calcSizeBinary(const UA_CreateSessionRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CreateSessionRequest_encodeBinary(const UA_CreateSessionRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CreateSessionRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CreateSessionRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST], NULL); -} - -/* CreateSessionResponse */ -static UA_INLINE size_t -UA_CreateSessionResponse_calcSizeBinary(const UA_CreateSessionResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_CreateSessionResponse_encodeBinary(const UA_CreateSessionResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CreateSessionResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CreateSessionResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE], NULL); -} - -/* UserIdentityToken */ -static UA_INLINE size_t -UA_UserIdentityToken_calcSizeBinary(const UA_UserIdentityToken *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_USERIDENTITYTOKEN]); -} -static UA_INLINE UA_StatusCode -UA_UserIdentityToken_encodeBinary(const UA_UserIdentityToken *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_USERIDENTITYTOKEN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UserIdentityToken_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UserIdentityToken *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_USERIDENTITYTOKEN], NULL); -} - -/* AnonymousIdentityToken */ -static UA_INLINE size_t -UA_AnonymousIdentityToken_calcSizeBinary(const UA_AnonymousIdentityToken *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]); -} -static UA_INLINE UA_StatusCode -UA_AnonymousIdentityToken_encodeBinary(const UA_AnonymousIdentityToken *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AnonymousIdentityToken_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AnonymousIdentityToken *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN], NULL); -} - -/* UserNameIdentityToken */ -static UA_INLINE size_t -UA_UserNameIdentityToken_calcSizeBinary(const UA_UserNameIdentityToken *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]); -} -static UA_INLINE UA_StatusCode -UA_UserNameIdentityToken_encodeBinary(const UA_UserNameIdentityToken *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UserNameIdentityToken_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UserNameIdentityToken *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN], NULL); -} - -/* X509IdentityToken */ -static UA_INLINE size_t -UA_X509IdentityToken_calcSizeBinary(const UA_X509IdentityToken *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]); -} -static UA_INLINE UA_StatusCode -UA_X509IdentityToken_encodeBinary(const UA_X509IdentityToken *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_X509IdentityToken_decodeBinary(const UA_ByteString *src, size_t *offset, UA_X509IdentityToken *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN], NULL); -} - -/* IssuedIdentityToken */ -static UA_INLINE size_t -UA_IssuedIdentityToken_calcSizeBinary(const UA_IssuedIdentityToken *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN]); -} -static UA_INLINE UA_StatusCode -UA_IssuedIdentityToken_encodeBinary(const UA_IssuedIdentityToken *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_IssuedIdentityToken_decodeBinary(const UA_ByteString *src, size_t *offset, UA_IssuedIdentityToken *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN], NULL); -} - -/* ActivateSessionRequest */ -static UA_INLINE size_t -UA_ActivateSessionRequest_calcSizeBinary(const UA_ActivateSessionRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_ActivateSessionRequest_encodeBinary(const UA_ActivateSessionRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ActivateSessionRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ActivateSessionRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST], NULL); -} - -/* ActivateSessionResponse */ -static UA_INLINE size_t -UA_ActivateSessionResponse_calcSizeBinary(const UA_ActivateSessionResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_ActivateSessionResponse_encodeBinary(const UA_ActivateSessionResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ActivateSessionResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ActivateSessionResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE], NULL); -} - -/* CloseSessionRequest */ -static UA_INLINE size_t -UA_CloseSessionRequest_calcSizeBinary(const UA_CloseSessionRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CloseSessionRequest_encodeBinary(const UA_CloseSessionRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CloseSessionRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CloseSessionRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST], NULL); -} - -/* CloseSessionResponse */ -static UA_INLINE size_t -UA_CloseSessionResponse_calcSizeBinary(const UA_CloseSessionResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_CloseSessionResponse_encodeBinary(const UA_CloseSessionResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CloseSessionResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CloseSessionResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE], NULL); -} - -/* NodeAttributesMask */ -static UA_INLINE size_t -UA_NodeAttributesMask_calcSizeBinary(const UA_NodeAttributesMask *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_NODEATTRIBUTESMASK]); -} -static UA_INLINE UA_StatusCode -UA_NodeAttributesMask_encodeBinary(const UA_NodeAttributesMask *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NODEATTRIBUTESMASK], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_NodeAttributesMask_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NodeAttributesMask *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NODEATTRIBUTESMASK], NULL); -} - -/* NodeAttributes */ -static UA_INLINE size_t -UA_NodeAttributes_calcSizeBinary(const UA_NodeAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_NODEATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_NodeAttributes_encodeBinary(const UA_NodeAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NODEATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_NodeAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NodeAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NODEATTRIBUTES], NULL); -} - -/* ObjectAttributes */ -static UA_INLINE size_t -UA_ObjectAttributes_calcSizeBinary(const UA_ObjectAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_ObjectAttributes_encodeBinary(const UA_ObjectAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ObjectAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ObjectAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL); -} - -/* VariableAttributes */ -static UA_INLINE size_t -UA_VariableAttributes_calcSizeBinary(const UA_VariableAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_VariableAttributes_encodeBinary(const UA_VariableAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_VariableAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_VariableAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL); -} - -/* MethodAttributes */ -static UA_INLINE size_t -UA_MethodAttributes_calcSizeBinary(const UA_MethodAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_METHODATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_MethodAttributes_encodeBinary(const UA_MethodAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_METHODATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MethodAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MethodAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_METHODATTRIBUTES], NULL); -} - -/* ObjectTypeAttributes */ -static UA_INLINE size_t -UA_ObjectTypeAttributes_calcSizeBinary(const UA_ObjectTypeAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_ObjectTypeAttributes_encodeBinary(const UA_ObjectTypeAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ObjectTypeAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ObjectTypeAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL); -} - -/* VariableTypeAttributes */ -static UA_INLINE size_t -UA_VariableTypeAttributes_calcSizeBinary(const UA_VariableTypeAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_VariableTypeAttributes_encodeBinary(const UA_VariableTypeAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_VariableTypeAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_VariableTypeAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], NULL); -} - -/* ReferenceTypeAttributes */ -static UA_INLINE size_t -UA_ReferenceTypeAttributes_calcSizeBinary(const UA_ReferenceTypeAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_ReferenceTypeAttributes_encodeBinary(const UA_ReferenceTypeAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReferenceTypeAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReferenceTypeAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], NULL); -} - -/* DataTypeAttributes */ -static UA_INLINE size_t -UA_DataTypeAttributes_calcSizeBinary(const UA_DataTypeAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_DataTypeAttributes_encodeBinary(const UA_DataTypeAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DataTypeAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataTypeAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], NULL); -} - -/* ViewAttributes */ -static UA_INLINE size_t -UA_ViewAttributes_calcSizeBinary(const UA_ViewAttributes *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_VIEWATTRIBUTES]); -} -static UA_INLINE UA_StatusCode -UA_ViewAttributes_encodeBinary(const UA_ViewAttributes *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ViewAttributes_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ViewAttributes *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], NULL); -} - -/* AddNodesItem */ -static UA_INLINE size_t -UA_AddNodesItem_calcSizeBinary(const UA_AddNodesItem *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESITEM]); -} -static UA_INLINE UA_StatusCode -UA_AddNodesItem_encodeBinary(const UA_AddNodesItem *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESITEM], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddNodesItem_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddNodesItem *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDNODESITEM], NULL); -} - -/* AddNodesResult */ -static UA_INLINE size_t -UA_AddNodesResult_calcSizeBinary(const UA_AddNodesResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESRESULT]); -} -static UA_INLINE UA_StatusCode -UA_AddNodesResult_encodeBinary(const UA_AddNodesResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddNodesResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddNodesResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDNODESRESULT], NULL); -} - -/* AddNodesRequest */ -static UA_INLINE size_t -UA_AddNodesRequest_calcSizeBinary(const UA_AddNodesRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_AddNodesRequest_encodeBinary(const UA_AddNodesRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddNodesRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddNodesRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDNODESREQUEST], NULL); -} - -/* AddNodesResponse */ -static UA_INLINE size_t -UA_AddNodesResponse_calcSizeBinary(const UA_AddNodesResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_AddNodesResponse_encodeBinary(const UA_AddNodesResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddNodesResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddNodesResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE], NULL); -} - -/* AddReferencesItem */ -static UA_INLINE size_t -UA_AddReferencesItem_calcSizeBinary(const UA_AddReferencesItem *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM]); -} -static UA_INLINE UA_StatusCode -UA_AddReferencesItem_encodeBinary(const UA_AddReferencesItem *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddReferencesItem_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddReferencesItem *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], NULL); -} - -/* AddReferencesRequest */ -static UA_INLINE size_t -UA_AddReferencesRequest_calcSizeBinary(const UA_AddReferencesRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_AddReferencesRequest_encodeBinary(const UA_AddReferencesRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddReferencesRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddReferencesRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST], NULL); -} - -/* AddReferencesResponse */ -static UA_INLINE size_t -UA_AddReferencesResponse_calcSizeBinary(const UA_AddReferencesResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_AddReferencesResponse_encodeBinary(const UA_AddReferencesResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AddReferencesResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AddReferencesResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE], NULL); -} - -/* DeleteNodesItem */ -static UA_INLINE size_t -UA_DeleteNodesItem_calcSizeBinary(const UA_DeleteNodesItem *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETENODESITEM]); -} -static UA_INLINE UA_StatusCode -UA_DeleteNodesItem_encodeBinary(const UA_DeleteNodesItem *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETENODESITEM], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteNodesItem_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteNodesItem *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETENODESITEM], NULL); -} - -/* DeleteNodesRequest */ -static UA_INLINE size_t -UA_DeleteNodesRequest_calcSizeBinary(const UA_DeleteNodesRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETENODESREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_DeleteNodesRequest_encodeBinary(const UA_DeleteNodesRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETENODESREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteNodesRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteNodesRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETENODESREQUEST], NULL); -} - -/* DeleteNodesResponse */ -static UA_INLINE size_t -UA_DeleteNodesResponse_calcSizeBinary(const UA_DeleteNodesResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_DeleteNodesResponse_encodeBinary(const UA_DeleteNodesResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteNodesResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteNodesResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE], NULL); -} - -/* DeleteReferencesItem */ -static UA_INLINE size_t -UA_DeleteReferencesItem_calcSizeBinary(const UA_DeleteReferencesItem *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM]); -} -static UA_INLINE UA_StatusCode -UA_DeleteReferencesItem_encodeBinary(const UA_DeleteReferencesItem *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteReferencesItem_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteReferencesItem *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], NULL); -} - -/* DeleteReferencesRequest */ -static UA_INLINE size_t -UA_DeleteReferencesRequest_calcSizeBinary(const UA_DeleteReferencesRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_DeleteReferencesRequest_encodeBinary(const UA_DeleteReferencesRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteReferencesRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteReferencesRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST], NULL); -} - -/* DeleteReferencesResponse */ -static UA_INLINE size_t -UA_DeleteReferencesResponse_calcSizeBinary(const UA_DeleteReferencesResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_DeleteReferencesResponse_encodeBinary(const UA_DeleteReferencesResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteReferencesResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteReferencesResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE], NULL); -} - -/* BrowseDirection */ -static UA_INLINE size_t -UA_BrowseDirection_calcSizeBinary(const UA_BrowseDirection *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSEDIRECTION]); -} -static UA_INLINE UA_StatusCode -UA_BrowseDirection_encodeBinary(const UA_BrowseDirection *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSEDIRECTION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseDirection_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseDirection *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSEDIRECTION], NULL); -} - -/* ViewDescription */ -static UA_INLINE size_t -UA_ViewDescription_calcSizeBinary(const UA_ViewDescription *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_VIEWDESCRIPTION]); -} -static UA_INLINE UA_StatusCode -UA_ViewDescription_encodeBinary(const UA_ViewDescription *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ViewDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ViewDescription *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], NULL); -} - -/* BrowseDescription */ -static UA_INLINE size_t -UA_BrowseDescription_calcSizeBinary(const UA_BrowseDescription *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION]); -} -static UA_INLINE UA_StatusCode -UA_BrowseDescription_encodeBinary(const UA_BrowseDescription *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseDescription *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], NULL); -} - -/* BrowseResultMask */ -static UA_INLINE size_t -UA_BrowseResultMask_calcSizeBinary(const UA_BrowseResultMask *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSERESULTMASK]); -} -static UA_INLINE UA_StatusCode -UA_BrowseResultMask_encodeBinary(const UA_BrowseResultMask *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSERESULTMASK], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseResultMask_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseResultMask *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSERESULTMASK], NULL); -} - -/* ReferenceDescription */ -static UA_INLINE size_t -UA_ReferenceDescription_calcSizeBinary(const UA_ReferenceDescription *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]); -} -static UA_INLINE UA_StatusCode -UA_ReferenceDescription_encodeBinary(const UA_ReferenceDescription *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReferenceDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReferenceDescription *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], NULL); -} - -/* BrowseResult */ -static UA_INLINE size_t -UA_BrowseResult_calcSizeBinary(const UA_BrowseResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSERESULT]); -} -static UA_INLINE UA_StatusCode -UA_BrowseResult_encodeBinary(const UA_BrowseResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSERESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSERESULT], NULL); -} - -/* BrowseRequest */ -static UA_INLINE size_t -UA_BrowseRequest_calcSizeBinary(const UA_BrowseRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSEREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_BrowseRequest_encodeBinary(const UA_BrowseRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSEREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSEREQUEST], NULL); -} - -/* BrowseResponse */ -static UA_INLINE size_t -UA_BrowseResponse_calcSizeBinary(const UA_BrowseResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSERESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_BrowseResponse_encodeBinary(const UA_BrowseResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSERESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSERESPONSE], NULL); -} - -/* BrowseNextRequest */ -static UA_INLINE size_t -UA_BrowseNextRequest_calcSizeBinary(const UA_BrowseNextRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_BrowseNextRequest_encodeBinary(const UA_BrowseNextRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseNextRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseNextRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], NULL); -} - -/* BrowseNextResponse */ -static UA_INLINE size_t -UA_BrowseNextResponse_calcSizeBinary(const UA_BrowseNextResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_BrowseNextResponse_encodeBinary(const UA_BrowseNextResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowseNextResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowseNextResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], NULL); -} - -/* RelativePathElement */ -static UA_INLINE size_t -UA_RelativePathElement_calcSizeBinary(const UA_RelativePathElement *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]); -} -static UA_INLINE UA_StatusCode -UA_RelativePathElement_encodeBinary(const UA_RelativePathElement *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RelativePathElement_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RelativePathElement *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT], NULL); -} - -/* RelativePath */ -static UA_INLINE size_t -UA_RelativePath_calcSizeBinary(const UA_RelativePath *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_RELATIVEPATH]); -} -static UA_INLINE UA_StatusCode -UA_RelativePath_encodeBinary(const UA_RelativePath *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_RELATIVEPATH], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RelativePath_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RelativePath *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_RELATIVEPATH], NULL); -} - -/* BrowsePath */ -static UA_INLINE size_t -UA_BrowsePath_calcSizeBinary(const UA_BrowsePath *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSEPATH]); -} -static UA_INLINE UA_StatusCode -UA_BrowsePath_encodeBinary(const UA_BrowsePath *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSEPATH], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowsePath_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowsePath *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSEPATH], NULL); -} - -/* BrowsePathTarget */ -static UA_INLINE size_t -UA_BrowsePathTarget_calcSizeBinary(const UA_BrowsePathTarget *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET]); -} -static UA_INLINE UA_StatusCode -UA_BrowsePathTarget_encodeBinary(const UA_BrowsePathTarget *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowsePathTarget_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowsePathTarget *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], NULL); -} - -/* BrowsePathResult */ -static UA_INLINE size_t -UA_BrowsePathResult_calcSizeBinary(const UA_BrowsePathResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]); -} -static UA_INLINE UA_StatusCode -UA_BrowsePathResult_encodeBinary(const UA_BrowsePathResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BrowsePathResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BrowsePathResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT], NULL); -} - -/* TranslateBrowsePathsToNodeIdsRequest */ -static UA_INLINE size_t -UA_TranslateBrowsePathsToNodeIdsRequest_calcSizeBinary(const UA_TranslateBrowsePathsToNodeIdsRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_TranslateBrowsePathsToNodeIdsRequest_encodeBinary(const UA_TranslateBrowsePathsToNodeIdsRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TranslateBrowsePathsToNodeIdsRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TranslateBrowsePathsToNodeIdsRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST], NULL); -} - -/* TranslateBrowsePathsToNodeIdsResponse */ -static UA_INLINE size_t -UA_TranslateBrowsePathsToNodeIdsResponse_calcSizeBinary(const UA_TranslateBrowsePathsToNodeIdsResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_TranslateBrowsePathsToNodeIdsResponse_encodeBinary(const UA_TranslateBrowsePathsToNodeIdsResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TranslateBrowsePathsToNodeIdsResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TranslateBrowsePathsToNodeIdsResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE], NULL); -} - -/* RegisterNodesRequest */ -static UA_INLINE size_t -UA_RegisterNodesRequest_calcSizeBinary(const UA_RegisterNodesRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_RegisterNodesRequest_encodeBinary(const UA_RegisterNodesRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RegisterNodesRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisterNodesRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST], NULL); -} - -/* RegisterNodesResponse */ -static UA_INLINE size_t -UA_RegisterNodesResponse_calcSizeBinary(const UA_RegisterNodesResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_RegisterNodesResponse_encodeBinary(const UA_RegisterNodesResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RegisterNodesResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisterNodesResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE], NULL); -} - -/* UnregisterNodesRequest */ -static UA_INLINE size_t -UA_UnregisterNodesRequest_calcSizeBinary(const UA_UnregisterNodesRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_UnregisterNodesRequest_encodeBinary(const UA_UnregisterNodesRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UnregisterNodesRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UnregisterNodesRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST], NULL); -} - -/* UnregisterNodesResponse */ -static UA_INLINE size_t -UA_UnregisterNodesResponse_calcSizeBinary(const UA_UnregisterNodesResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_UnregisterNodesResponse_encodeBinary(const UA_UnregisterNodesResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UnregisterNodesResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UnregisterNodesResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE], NULL); -} - -/* FilterOperator */ -static UA_INLINE size_t -UA_FilterOperator_calcSizeBinary(const UA_FilterOperator *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_FILTEROPERATOR]); -} -static UA_INLINE UA_StatusCode -UA_FilterOperator_encodeBinary(const UA_FilterOperator *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FILTEROPERATOR], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_FilterOperator_decodeBinary(const UA_ByteString *src, size_t *offset, UA_FilterOperator *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FILTEROPERATOR], NULL); -} - -/* ContentFilterElement */ -static UA_INLINE size_t -UA_ContentFilterElement_calcSizeBinary(const UA_ContentFilterElement *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]); -} -static UA_INLINE UA_StatusCode -UA_ContentFilterElement_encodeBinary(const UA_ContentFilterElement *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ContentFilterElement_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ContentFilterElement *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT], NULL); -} - -/* ContentFilter */ -static UA_INLINE size_t -UA_ContentFilter_calcSizeBinary(const UA_ContentFilter *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTER]); -} -static UA_INLINE UA_StatusCode -UA_ContentFilter_encodeBinary(const UA_ContentFilter *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ContentFilter_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ContentFilter *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CONTENTFILTER], NULL); -} - -/* FilterOperand */ -static UA_INLINE size_t -UA_FilterOperand_calcSizeBinary(const UA_FilterOperand *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_FILTEROPERAND]); -} -static UA_INLINE UA_StatusCode -UA_FilterOperand_encodeBinary(const UA_FilterOperand *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FILTEROPERAND], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_FilterOperand_decodeBinary(const UA_ByteString *src, size_t *offset, UA_FilterOperand *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FILTEROPERAND], NULL); -} - -/* ElementOperand */ -static UA_INLINE size_t -UA_ElementOperand_calcSizeBinary(const UA_ElementOperand *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ELEMENTOPERAND]); -} -static UA_INLINE UA_StatusCode -UA_ElementOperand_encodeBinary(const UA_ElementOperand *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ELEMENTOPERAND], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ElementOperand_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ElementOperand *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ELEMENTOPERAND], NULL); -} - -/* LiteralOperand */ -static UA_INLINE size_t -UA_LiteralOperand_calcSizeBinary(const UA_LiteralOperand *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_LITERALOPERAND]); -} -static UA_INLINE UA_StatusCode -UA_LiteralOperand_encodeBinary(const UA_LiteralOperand *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_LITERALOPERAND], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_LiteralOperand_decodeBinary(const UA_ByteString *src, size_t *offset, UA_LiteralOperand *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_LITERALOPERAND], NULL); -} - -/* AttributeOperand */ -static UA_INLINE size_t -UA_AttributeOperand_calcSizeBinary(const UA_AttributeOperand *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]); -} -static UA_INLINE UA_StatusCode -UA_AttributeOperand_encodeBinary(const UA_AttributeOperand *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AttributeOperand_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AttributeOperand *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND], NULL); -} - -/* SimpleAttributeOperand */ -static UA_INLINE size_t -UA_SimpleAttributeOperand_calcSizeBinary(const UA_SimpleAttributeOperand *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]); -} -static UA_INLINE UA_StatusCode -UA_SimpleAttributeOperand_encodeBinary(const UA_SimpleAttributeOperand *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SimpleAttributeOperand_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SimpleAttributeOperand *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], NULL); -} - -/* ContentFilterElementResult */ -static UA_INLINE size_t -UA_ContentFilterElementResult_calcSizeBinary(const UA_ContentFilterElementResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT]); -} -static UA_INLINE UA_StatusCode -UA_ContentFilterElementResult_encodeBinary(const UA_ContentFilterElementResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ContentFilterElementResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ContentFilterElementResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT], NULL); -} - -/* ContentFilterResult */ -static UA_INLINE size_t -UA_ContentFilterResult_calcSizeBinary(const UA_ContentFilterResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT]); -} -static UA_INLINE UA_StatusCode -UA_ContentFilterResult_encodeBinary(const UA_ContentFilterResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ContentFilterResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ContentFilterResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], NULL); -} - -/* TimestampsToReturn */ -static UA_INLINE size_t -UA_TimestampsToReturn_calcSizeBinary(const UA_TimestampsToReturn *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN]); -} -static UA_INLINE UA_StatusCode -UA_TimestampsToReturn_encodeBinary(const UA_TimestampsToReturn *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TimestampsToReturn_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TimestampsToReturn *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], NULL); -} - -/* ReadValueId */ -static UA_INLINE size_t -UA_ReadValueId_calcSizeBinary(const UA_ReadValueId *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READVALUEID]); -} -static UA_INLINE UA_StatusCode -UA_ReadValueId_encodeBinary(const UA_ReadValueId *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READVALUEID], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadValueId_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadValueId *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READVALUEID], NULL); -} - -/* ReadRequest */ -static UA_INLINE size_t -UA_ReadRequest_calcSizeBinary(const UA_ReadRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_ReadRequest_encodeBinary(const UA_ReadRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READREQUEST], NULL); -} - -/* ReadResponse */ -static UA_INLINE size_t -UA_ReadResponse_calcSizeBinary(const UA_ReadResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_ReadResponse_encodeBinary(const UA_ReadResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READRESPONSE], NULL); -} - -/* HistoryReadValueId */ -static UA_INLINE size_t -UA_HistoryReadValueId_calcSizeBinary(const UA_HistoryReadValueId *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADVALUEID]); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadValueId_encodeBinary(const UA_HistoryReadValueId *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADVALUEID], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadValueId_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryReadValueId *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYREADVALUEID], NULL); -} - -/* HistoryReadResult */ -static UA_INLINE size_t -UA_HistoryReadResult_calcSizeBinary(const UA_HistoryReadResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADRESULT]); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadResult_encodeBinary(const UA_HistoryReadResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryReadResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYREADRESULT], NULL); -} - -/* ReadRawModifiedDetails */ -static UA_INLINE size_t -UA_ReadRawModifiedDetails_calcSizeBinary(const UA_ReadRawModifiedDetails *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS]); -} -static UA_INLINE UA_StatusCode -UA_ReadRawModifiedDetails_encodeBinary(const UA_ReadRawModifiedDetails *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadRawModifiedDetails_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadRawModifiedDetails *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS], NULL); -} - -/* ReadAtTimeDetails */ -static UA_INLINE size_t -UA_ReadAtTimeDetails_calcSizeBinary(const UA_ReadAtTimeDetails *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READATTIMEDETAILS]); -} -static UA_INLINE UA_StatusCode -UA_ReadAtTimeDetails_encodeBinary(const UA_ReadAtTimeDetails *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READATTIMEDETAILS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadAtTimeDetails_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadAtTimeDetails *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READATTIMEDETAILS], NULL); -} - -/* HistoryData */ -static UA_INLINE size_t -UA_HistoryData_calcSizeBinary(const UA_HistoryData *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYDATA]); -} -static UA_INLINE UA_StatusCode -UA_HistoryData_encodeBinary(const UA_HistoryData *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYDATA], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryData_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryData *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYDATA], NULL); -} - -/* HistoryReadRequest */ -static UA_INLINE size_t -UA_HistoryReadRequest_calcSizeBinary(const UA_HistoryReadRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadRequest_encodeBinary(const UA_HistoryReadRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryReadRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], NULL); -} - -/* HistoryReadResponse */ -static UA_INLINE size_t -UA_HistoryReadResponse_calcSizeBinary(const UA_HistoryReadResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadResponse_encodeBinary(const UA_HistoryReadResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryReadResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryReadResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE], NULL); -} - -/* WriteValue */ -static UA_INLINE size_t -UA_WriteValue_calcSizeBinary(const UA_WriteValue *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_WRITEVALUE]); -} -static UA_INLINE UA_StatusCode -UA_WriteValue_encodeBinary(const UA_WriteValue *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_WRITEVALUE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_WriteValue_decodeBinary(const UA_ByteString *src, size_t *offset, UA_WriteValue *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_WRITEVALUE], NULL); -} - -/* WriteRequest */ -static UA_INLINE size_t -UA_WriteRequest_calcSizeBinary(const UA_WriteRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_WRITEREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_WriteRequest_encodeBinary(const UA_WriteRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_WRITEREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_WriteRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_WriteRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_WRITEREQUEST], NULL); -} - -/* WriteResponse */ -static UA_INLINE size_t -UA_WriteResponse_calcSizeBinary(const UA_WriteResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_WRITERESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_WriteResponse_encodeBinary(const UA_WriteResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_WRITERESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_WriteResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_WriteResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_WRITERESPONSE], NULL); -} - -/* HistoryUpdateType */ -static UA_INLINE size_t -UA_HistoryUpdateType_calcSizeBinary(const UA_HistoryUpdateType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATETYPE]); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateType_encodeBinary(const UA_HistoryUpdateType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATETYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryUpdateType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYUPDATETYPE], NULL); -} - -/* PerformUpdateType */ -static UA_INLINE size_t -UA_PerformUpdateType_calcSizeBinary(const UA_PerformUpdateType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE]); -} -static UA_INLINE UA_StatusCode -UA_PerformUpdateType_encodeBinary(const UA_PerformUpdateType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_PerformUpdateType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_PerformUpdateType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], NULL); -} - -/* UpdateDataDetails */ -static UA_INLINE size_t -UA_UpdateDataDetails_calcSizeBinary(const UA_UpdateDataDetails *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_UPDATEDATADETAILS]); -} -static UA_INLINE UA_StatusCode -UA_UpdateDataDetails_encodeBinary(const UA_UpdateDataDetails *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_UPDATEDATADETAILS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_UpdateDataDetails_decodeBinary(const UA_ByteString *src, size_t *offset, UA_UpdateDataDetails *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_UPDATEDATADETAILS], NULL); -} - -/* DeleteRawModifiedDetails */ -static UA_INLINE size_t -UA_DeleteRawModifiedDetails_calcSizeBinary(const UA_DeleteRawModifiedDetails *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS]); -} -static UA_INLINE UA_StatusCode -UA_DeleteRawModifiedDetails_encodeBinary(const UA_DeleteRawModifiedDetails *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteRawModifiedDetails_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteRawModifiedDetails *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS], NULL); -} - -/* HistoryUpdateResult */ -static UA_INLINE size_t -UA_HistoryUpdateResult_calcSizeBinary(const UA_HistoryUpdateResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT]); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateResult_encodeBinary(const UA_HistoryUpdateResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryUpdateResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT], NULL); -} - -/* HistoryUpdateRequest */ -static UA_INLINE size_t -UA_HistoryUpdateRequest_calcSizeBinary(const UA_HistoryUpdateRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateRequest_encodeBinary(const UA_HistoryUpdateRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryUpdateRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST], NULL); -} - -/* HistoryUpdateResponse */ -static UA_INLINE size_t -UA_HistoryUpdateResponse_calcSizeBinary(const UA_HistoryUpdateResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateResponse_encodeBinary(const UA_HistoryUpdateResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryUpdateResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryUpdateResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE], NULL); -} - -/* CallMethodRequest */ -static UA_INLINE size_t -UA_CallMethodRequest_calcSizeBinary(const UA_CallMethodRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CallMethodRequest_encodeBinary(const UA_CallMethodRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CallMethodRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CallMethodRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], NULL); -} - -/* CallMethodResult */ -static UA_INLINE size_t -UA_CallMethodResult_calcSizeBinary(const UA_CallMethodResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]); -} -static UA_INLINE UA_StatusCode -UA_CallMethodResult_encodeBinary(const UA_CallMethodResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CALLMETHODRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CallMethodResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CallMethodResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CALLMETHODRESULT], NULL); -} - -/* CallRequest */ -static UA_INLINE size_t -UA_CallRequest_calcSizeBinary(const UA_CallRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CALLREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CallRequest_encodeBinary(const UA_CallRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CALLREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CallRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CallRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CALLREQUEST], NULL); -} - -/* CallResponse */ -static UA_INLINE size_t -UA_CallResponse_calcSizeBinary(const UA_CallResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CALLRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_CallResponse_encodeBinary(const UA_CallResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CALLRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CallResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CallResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CALLRESPONSE], NULL); -} - -/* MonitoringMode */ -static UA_INLINE size_t -UA_MonitoringMode_calcSizeBinary(const UA_MonitoringMode *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITORINGMODE]); -} -static UA_INLINE UA_StatusCode -UA_MonitoringMode_encodeBinary(const UA_MonitoringMode *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITORINGMODE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoringMode_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoringMode *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITORINGMODE], NULL); -} - -/* DataChangeTrigger */ -static UA_INLINE size_t -UA_DataChangeTrigger_calcSizeBinary(const UA_DataChangeTrigger *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DATACHANGETRIGGER]); -} -static UA_INLINE UA_StatusCode -UA_DataChangeTrigger_encodeBinary(const UA_DataChangeTrigger *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DATACHANGETRIGGER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DataChangeTrigger_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataChangeTrigger *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DATACHANGETRIGGER], NULL); -} - -/* DeadbandType */ -static UA_INLINE size_t -UA_DeadbandType_calcSizeBinary(const UA_DeadbandType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DEADBANDTYPE]); -} -static UA_INLINE UA_StatusCode -UA_DeadbandType_encodeBinary(const UA_DeadbandType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DEADBANDTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeadbandType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeadbandType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DEADBANDTYPE], NULL); -} - -/* DataChangeFilter */ -static UA_INLINE size_t -UA_DataChangeFilter_calcSizeBinary(const UA_DataChangeFilter *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DATACHANGEFILTER]); -} -static UA_INLINE UA_StatusCode -UA_DataChangeFilter_encodeBinary(const UA_DataChangeFilter *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DATACHANGEFILTER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DataChangeFilter_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataChangeFilter *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DATACHANGEFILTER], NULL); -} - -/* EventFilter */ -static UA_INLINE size_t -UA_EventFilter_calcSizeBinary(const UA_EventFilter *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EVENTFILTER]); -} -static UA_INLINE UA_StatusCode -UA_EventFilter_encodeBinary(const UA_EventFilter *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EVENTFILTER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EventFilter_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EventFilter *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EVENTFILTER], NULL); -} - -/* AggregateConfiguration */ -static UA_INLINE size_t -UA_AggregateConfiguration_calcSizeBinary(const UA_AggregateConfiguration *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION]); -} -static UA_INLINE UA_StatusCode -UA_AggregateConfiguration_encodeBinary(const UA_AggregateConfiguration *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AggregateConfiguration_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AggregateConfiguration *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], NULL); -} - -/* AggregateFilter */ -static UA_INLINE size_t -UA_AggregateFilter_calcSizeBinary(const UA_AggregateFilter *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_AGGREGATEFILTER]); -} -static UA_INLINE UA_StatusCode -UA_AggregateFilter_encodeBinary(const UA_AggregateFilter *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_AGGREGATEFILTER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AggregateFilter_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AggregateFilter *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_AGGREGATEFILTER], NULL); -} - -/* EventFilterResult */ -static UA_INLINE size_t -UA_EventFilterResult_calcSizeBinary(const UA_EventFilterResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EVENTFILTERRESULT]); -} -static UA_INLINE UA_StatusCode -UA_EventFilterResult_encodeBinary(const UA_EventFilterResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EVENTFILTERRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EventFilterResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EventFilterResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EVENTFILTERRESULT], NULL); -} - -/* MonitoringParameters */ -static UA_INLINE size_t -UA_MonitoringParameters_calcSizeBinary(const UA_MonitoringParameters *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS]); -} -static UA_INLINE UA_StatusCode -UA_MonitoringParameters_encodeBinary(const UA_MonitoringParameters *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoringParameters_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoringParameters *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], NULL); -} - -/* MonitoredItemCreateRequest */ -static UA_INLINE size_t -UA_MonitoredItemCreateRequest_calcSizeBinary(const UA_MonitoredItemCreateRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemCreateRequest_encodeBinary(const UA_MonitoredItemCreateRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemCreateRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoredItemCreateRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], NULL); -} - -/* MonitoredItemCreateResult */ -static UA_INLINE size_t -UA_MonitoredItemCreateResult_calcSizeBinary(const UA_MonitoredItemCreateResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemCreateResult_encodeBinary(const UA_MonitoredItemCreateResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemCreateResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoredItemCreateResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], NULL); -} - -/* CreateMonitoredItemsRequest */ -static UA_INLINE size_t -UA_CreateMonitoredItemsRequest_calcSizeBinary(const UA_CreateMonitoredItemsRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CreateMonitoredItemsRequest_encodeBinary(const UA_CreateMonitoredItemsRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CreateMonitoredItemsRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CreateMonitoredItemsRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], NULL); -} - -/* CreateMonitoredItemsResponse */ -static UA_INLINE size_t -UA_CreateMonitoredItemsResponse_calcSizeBinary(const UA_CreateMonitoredItemsResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_CreateMonitoredItemsResponse_encodeBinary(const UA_CreateMonitoredItemsResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CreateMonitoredItemsResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CreateMonitoredItemsResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE], NULL); -} - -/* MonitoredItemModifyRequest */ -static UA_INLINE size_t -UA_MonitoredItemModifyRequest_calcSizeBinary(const UA_MonitoredItemModifyRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemModifyRequest_encodeBinary(const UA_MonitoredItemModifyRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemModifyRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoredItemModifyRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], NULL); -} - -/* MonitoredItemModifyResult */ -static UA_INLINE size_t -UA_MonitoredItemModifyResult_calcSizeBinary(const UA_MonitoredItemModifyResult *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemModifyResult_encodeBinary(const UA_MonitoredItemModifyResult *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemModifyResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoredItemModifyResult *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT], NULL); -} - -/* ModifyMonitoredItemsRequest */ -static UA_INLINE size_t -UA_ModifyMonitoredItemsRequest_calcSizeBinary(const UA_ModifyMonitoredItemsRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_ModifyMonitoredItemsRequest_encodeBinary(const UA_ModifyMonitoredItemsRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ModifyMonitoredItemsRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ModifyMonitoredItemsRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], NULL); -} - -/* ModifyMonitoredItemsResponse */ -static UA_INLINE size_t -UA_ModifyMonitoredItemsResponse_calcSizeBinary(const UA_ModifyMonitoredItemsResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_ModifyMonitoredItemsResponse_encodeBinary(const UA_ModifyMonitoredItemsResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ModifyMonitoredItemsResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ModifyMonitoredItemsResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE], NULL); -} - -/* SetMonitoringModeRequest */ -static UA_INLINE size_t -UA_SetMonitoringModeRequest_calcSizeBinary(const UA_SetMonitoringModeRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_SetMonitoringModeRequest_encodeBinary(const UA_SetMonitoringModeRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SetMonitoringModeRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SetMonitoringModeRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], NULL); -} - -/* SetMonitoringModeResponse */ -static UA_INLINE size_t -UA_SetMonitoringModeResponse_calcSizeBinary(const UA_SetMonitoringModeResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_SetMonitoringModeResponse_encodeBinary(const UA_SetMonitoringModeResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SetMonitoringModeResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SetMonitoringModeResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE], NULL); -} - -/* SetTriggeringRequest */ -static UA_INLINE size_t -UA_SetTriggeringRequest_calcSizeBinary(const UA_SetTriggeringRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_SetTriggeringRequest_encodeBinary(const UA_SetTriggeringRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SetTriggeringRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SetTriggeringRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], NULL); -} - -/* SetTriggeringResponse */ -static UA_INLINE size_t -UA_SetTriggeringResponse_calcSizeBinary(const UA_SetTriggeringResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_SetTriggeringResponse_encodeBinary(const UA_SetTriggeringResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SetTriggeringResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SetTriggeringResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE], NULL); -} - -/* DeleteMonitoredItemsRequest */ -static UA_INLINE size_t -UA_DeleteMonitoredItemsRequest_calcSizeBinary(const UA_DeleteMonitoredItemsRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_DeleteMonitoredItemsRequest_encodeBinary(const UA_DeleteMonitoredItemsRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteMonitoredItemsRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteMonitoredItemsRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], NULL); -} - -/* DeleteMonitoredItemsResponse */ -static UA_INLINE size_t -UA_DeleteMonitoredItemsResponse_calcSizeBinary(const UA_DeleteMonitoredItemsResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_DeleteMonitoredItemsResponse_encodeBinary(const UA_DeleteMonitoredItemsResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteMonitoredItemsResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteMonitoredItemsResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE], NULL); -} - -/* CreateSubscriptionRequest */ -static UA_INLINE size_t -UA_CreateSubscriptionRequest_calcSizeBinary(const UA_CreateSubscriptionRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_CreateSubscriptionRequest_encodeBinary(const UA_CreateSubscriptionRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CreateSubscriptionRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CreateSubscriptionRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], NULL); -} - -/* CreateSubscriptionResponse */ -static UA_INLINE size_t -UA_CreateSubscriptionResponse_calcSizeBinary(const UA_CreateSubscriptionResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_CreateSubscriptionResponse_encodeBinary(const UA_CreateSubscriptionResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_CreateSubscriptionResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_CreateSubscriptionResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE], NULL); -} - -/* ModifySubscriptionRequest */ -static UA_INLINE size_t -UA_ModifySubscriptionRequest_calcSizeBinary(const UA_ModifySubscriptionRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_ModifySubscriptionRequest_encodeBinary(const UA_ModifySubscriptionRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ModifySubscriptionRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ModifySubscriptionRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], NULL); -} - -/* ModifySubscriptionResponse */ -static UA_INLINE size_t -UA_ModifySubscriptionResponse_calcSizeBinary(const UA_ModifySubscriptionResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_ModifySubscriptionResponse_encodeBinary(const UA_ModifySubscriptionResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ModifySubscriptionResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ModifySubscriptionResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE], NULL); -} - -/* SetPublishingModeRequest */ -static UA_INLINE size_t -UA_SetPublishingModeRequest_calcSizeBinary(const UA_SetPublishingModeRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_SetPublishingModeRequest_encodeBinary(const UA_SetPublishingModeRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SetPublishingModeRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SetPublishingModeRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST], NULL); -} - -/* SetPublishingModeResponse */ -static UA_INLINE size_t -UA_SetPublishingModeResponse_calcSizeBinary(const UA_SetPublishingModeResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_SetPublishingModeResponse_encodeBinary(const UA_SetPublishingModeResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SetPublishingModeResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SetPublishingModeResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE], NULL); -} - -/* NotificationMessage */ -static UA_INLINE size_t -UA_NotificationMessage_calcSizeBinary(const UA_NotificationMessage *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE]); -} -static UA_INLINE UA_StatusCode -UA_NotificationMessage_encodeBinary(const UA_NotificationMessage *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_NotificationMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NotificationMessage *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], NULL); -} - -/* MonitoredItemNotification */ -static UA_INLINE size_t -UA_MonitoredItemNotification_calcSizeBinary(const UA_MonitoredItemNotification *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemNotification_encodeBinary(const UA_MonitoredItemNotification *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MonitoredItemNotification_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MonitoredItemNotification *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION], NULL); -} - -/* EventFieldList */ -static UA_INLINE size_t -UA_EventFieldList_calcSizeBinary(const UA_EventFieldList *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EVENTFIELDLIST]); -} -static UA_INLINE UA_StatusCode -UA_EventFieldList_encodeBinary(const UA_EventFieldList *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EVENTFIELDLIST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EventFieldList_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EventFieldList *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EVENTFIELDLIST], NULL); -} - -/* HistoryEventFieldList */ -static UA_INLINE size_t -UA_HistoryEventFieldList_calcSizeBinary(const UA_HistoryEventFieldList *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST]); -} -static UA_INLINE UA_StatusCode -UA_HistoryEventFieldList_encodeBinary(const UA_HistoryEventFieldList *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryEventFieldList_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryEventFieldList *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST], NULL); -} - -/* StatusChangeNotification */ -static UA_INLINE size_t -UA_StatusChangeNotification_calcSizeBinary(const UA_StatusChangeNotification *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]); -} -static UA_INLINE UA_StatusCode -UA_StatusChangeNotification_encodeBinary(const UA_StatusChangeNotification *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_StatusChangeNotification_decodeBinary(const UA_ByteString *src, size_t *offset, UA_StatusChangeNotification *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION], NULL); -} - -/* SubscriptionAcknowledgement */ -static UA_INLINE size_t -UA_SubscriptionAcknowledgement_calcSizeBinary(const UA_SubscriptionAcknowledgement *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT]); -} -static UA_INLINE UA_StatusCode -UA_SubscriptionAcknowledgement_encodeBinary(const UA_SubscriptionAcknowledgement *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SubscriptionAcknowledgement_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SubscriptionAcknowledgement *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT], NULL); -} - -/* PublishRequest */ -static UA_INLINE size_t -UA_PublishRequest_calcSizeBinary(const UA_PublishRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_PUBLISHREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_PublishRequest_encodeBinary(const UA_PublishRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_PUBLISHREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_PublishRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_PublishRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_PUBLISHREQUEST], NULL); -} - -/* PublishResponse */ -static UA_INLINE size_t -UA_PublishResponse_calcSizeBinary(const UA_PublishResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_PublishResponse_encodeBinary(const UA_PublishResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_PublishResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_PublishResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], NULL); -} - -/* RepublishRequest */ -static UA_INLINE size_t -UA_RepublishRequest_calcSizeBinary(const UA_RepublishRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REPUBLISHREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_RepublishRequest_encodeBinary(const UA_RepublishRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REPUBLISHREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RepublishRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RepublishRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REPUBLISHREQUEST], NULL); -} - -/* RepublishResponse */ -static UA_INLINE size_t -UA_RepublishResponse_calcSizeBinary(const UA_RepublishResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_RepublishResponse_encodeBinary(const UA_RepublishResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RepublishResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RepublishResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE], NULL); -} - -/* DeleteSubscriptionsRequest */ -static UA_INLINE size_t -UA_DeleteSubscriptionsRequest_calcSizeBinary(const UA_DeleteSubscriptionsRequest *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST]); -} -static UA_INLINE UA_StatusCode -UA_DeleteSubscriptionsRequest_encodeBinary(const UA_DeleteSubscriptionsRequest *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteSubscriptionsRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteSubscriptionsRequest *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], NULL); -} - -/* DeleteSubscriptionsResponse */ -static UA_INLINE size_t -UA_DeleteSubscriptionsResponse_calcSizeBinary(const UA_DeleteSubscriptionsResponse *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]); -} -static UA_INLINE UA_StatusCode -UA_DeleteSubscriptionsResponse_encodeBinary(const UA_DeleteSubscriptionsResponse *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DeleteSubscriptionsResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DeleteSubscriptionsResponse *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE], NULL); -} - -/* BuildInfo */ -static UA_INLINE size_t -UA_BuildInfo_calcSizeBinary(const UA_BuildInfo *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_BUILDINFO]); -} -static UA_INLINE UA_StatusCode -UA_BuildInfo_encodeBinary(const UA_BuildInfo *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_BUILDINFO], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_BuildInfo_decodeBinary(const UA_ByteString *src, size_t *offset, UA_BuildInfo *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_BUILDINFO], NULL); -} - -/* RedundancySupport */ -static UA_INLINE size_t -UA_RedundancySupport_calcSizeBinary(const UA_RedundancySupport *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]); -} -static UA_INLINE UA_StatusCode -UA_RedundancySupport_encodeBinary(const UA_RedundancySupport *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_RedundancySupport_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RedundancySupport *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT], NULL); -} - -/* ServerState */ -static UA_INLINE size_t -UA_ServerState_calcSizeBinary(const UA_ServerState *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SERVERSTATE]); -} -static UA_INLINE UA_StatusCode -UA_ServerState_encodeBinary(const UA_ServerState *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SERVERSTATE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ServerState_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ServerState *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SERVERSTATE], NULL); -} - -/* ServerDiagnosticsSummaryDataType */ -static UA_INLINE size_t -UA_ServerDiagnosticsSummaryDataType_calcSizeBinary(const UA_ServerDiagnosticsSummaryDataType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE]); -} -static UA_INLINE UA_StatusCode -UA_ServerDiagnosticsSummaryDataType_encodeBinary(const UA_ServerDiagnosticsSummaryDataType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ServerDiagnosticsSummaryDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ServerDiagnosticsSummaryDataType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE], NULL); -} - -/* ServerStatusDataType */ -static UA_INLINE size_t -UA_ServerStatusDataType_calcSizeBinary(const UA_ServerStatusDataType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE]); -} -static UA_INLINE UA_StatusCode -UA_ServerStatusDataType_encodeBinary(const UA_ServerStatusDataType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ServerStatusDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ServerStatusDataType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE], NULL); -} - -/* Range */ -static UA_INLINE size_t -UA_Range_calcSizeBinary(const UA_Range *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_RANGE]); -} -static UA_INLINE UA_StatusCode -UA_Range_encodeBinary(const UA_Range *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_RANGE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_Range_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Range *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_RANGE], NULL); -} - -/* EUInformation */ -static UA_INLINE size_t -UA_EUInformation_calcSizeBinary(const UA_EUInformation *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EUINFORMATION]); -} -static UA_INLINE UA_StatusCode -UA_EUInformation_encodeBinary(const UA_EUInformation *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EUINFORMATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EUInformation_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EUInformation *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EUINFORMATION], NULL); -} - -/* AxisScaleEnumeration */ -static UA_INLINE size_t -UA_AxisScaleEnumeration_calcSizeBinary(const UA_AxisScaleEnumeration *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION]); -} -static UA_INLINE UA_StatusCode -UA_AxisScaleEnumeration_encodeBinary(const UA_AxisScaleEnumeration *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AxisScaleEnumeration_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AxisScaleEnumeration *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION], NULL); -} - -/* ComplexNumberType */ -static UA_INLINE size_t -UA_ComplexNumberType_calcSizeBinary(const UA_ComplexNumberType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]); -} -static UA_INLINE UA_StatusCode -UA_ComplexNumberType_encodeBinary(const UA_ComplexNumberType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ComplexNumberType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ComplexNumberType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE], NULL); -} - -/* DoubleComplexNumberType */ -static UA_INLINE size_t -UA_DoubleComplexNumberType_calcSizeBinary(const UA_DoubleComplexNumberType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE]); -} -static UA_INLINE UA_StatusCode -UA_DoubleComplexNumberType_encodeBinary(const UA_DoubleComplexNumberType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DoubleComplexNumberType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DoubleComplexNumberType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE], NULL); -} - -/* AxisInformation */ -static UA_INLINE size_t -UA_AxisInformation_calcSizeBinary(const UA_AxisInformation *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_AXISINFORMATION]); -} -static UA_INLINE UA_StatusCode -UA_AxisInformation_encodeBinary(const UA_AxisInformation *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_AXISINFORMATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AxisInformation_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AxisInformation *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_AXISINFORMATION], NULL); -} - -/* XVType */ -static UA_INLINE size_t -UA_XVType_calcSizeBinary(const UA_XVType *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_XVTYPE]); -} -static UA_INLINE UA_StatusCode -UA_XVType_encodeBinary(const UA_XVType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_XVTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_XVType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_XVType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_XVTYPE], NULL); -} - -/* EnumDefinition */ -static UA_INLINE size_t -UA_EnumDefinition_calcSizeBinary(const UA_EnumDefinition *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_ENUMDEFINITION]); -} -static UA_INLINE UA_StatusCode -UA_EnumDefinition_encodeBinary(const UA_EnumDefinition *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ENUMDEFINITION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EnumDefinition_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EnumDefinition *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ENUMDEFINITION], NULL); -} - -/* ReadEventDetails */ -static UA_INLINE size_t -UA_ReadEventDetails_calcSizeBinary(const UA_ReadEventDetails *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READEVENTDETAILS]); -} -static UA_INLINE UA_StatusCode -UA_ReadEventDetails_encodeBinary(const UA_ReadEventDetails *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READEVENTDETAILS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadEventDetails_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadEventDetails *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READEVENTDETAILS], NULL); -} - -/* ReadProcessedDetails */ -static UA_INLINE size_t -UA_ReadProcessedDetails_calcSizeBinary(const UA_ReadProcessedDetails *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_READPROCESSEDDETAILS]); -} -static UA_INLINE UA_StatusCode -UA_ReadProcessedDetails_encodeBinary(const UA_ReadProcessedDetails *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_READPROCESSEDDETAILS], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ReadProcessedDetails_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReadProcessedDetails *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_READPROCESSEDDETAILS], NULL); -} - -/* ModificationInfo */ -static UA_INLINE size_t -UA_ModificationInfo_calcSizeBinary(const UA_ModificationInfo *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_MODIFICATIONINFO]); -} -static UA_INLINE UA_StatusCode -UA_ModificationInfo_encodeBinary(const UA_ModificationInfo *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MODIFICATIONINFO], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ModificationInfo_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ModificationInfo *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MODIFICATIONINFO], NULL); -} - -/* HistoryModifiedData */ -static UA_INLINE size_t -UA_HistoryModifiedData_calcSizeBinary(const UA_HistoryModifiedData *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA]); -} -static UA_INLINE UA_StatusCode -UA_HistoryModifiedData_encodeBinary(const UA_HistoryModifiedData *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryModifiedData_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryModifiedData *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA], NULL); -} - -/* HistoryEvent */ -static UA_INLINE size_t -UA_HistoryEvent_calcSizeBinary(const UA_HistoryEvent *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_HISTORYEVENT]); -} -static UA_INLINE UA_StatusCode -UA_HistoryEvent_encodeBinary(const UA_HistoryEvent *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_HISTORYEVENT], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_HistoryEvent_decodeBinary(const UA_ByteString *src, size_t *offset, UA_HistoryEvent *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_HISTORYEVENT], NULL); -} - -/* DataChangeNotification */ -static UA_INLINE size_t -UA_DataChangeNotification_calcSizeBinary(const UA_DataChangeNotification *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]); -} -static UA_INLINE UA_StatusCode -UA_DataChangeNotification_encodeBinary(const UA_DataChangeNotification *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_DataChangeNotification_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataChangeNotification *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION], NULL); -} - -/* EventNotificationList */ -static UA_INLINE size_t -UA_EventNotificationList_calcSizeBinary(const UA_EventNotificationList *src) { - return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]); -} -static UA_INLINE UA_StatusCode -UA_EventNotificationList_encodeBinary(const UA_EventNotificationList *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_EventNotificationList_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EventNotificationList *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST], NULL); -} - - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/transport_generated.h" ***********************************/ - -/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_datatypes.py - * on host mintaka by user pdie at 2021-06-21 11:34:37 */ +#endif -#ifdef UA_ENABLE_AMALGAMATION -#else -#endif _UA_BEGIN_DECLS @@ -3962,6 +1245,7 @@ typedef enum { UA_MESSAGETYPE_OPN = 0x4E504F, UA_MESSAGETYPE_CLO = 0x4F4C43, UA_MESSAGETYPE_ERR = 0x525245, + UA_MESSAGETYPE_INVALID = 0x0, __UA_MESSAGETYPE_FORCE32BIT = 0x7fffffff } UA_MessageType; UA_STATIC_ASSERT(sizeof(UA_MessageType) == sizeof(UA_Int32), enum_must_be_32bit); @@ -4036,7 +1320,7 @@ typedef struct { /** * AsymmetricAlgorithmSecurityHeader * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Security Header */ + * Asymmetric Security Header */ typedef struct { UA_ByteString securityPolicyUri; UA_ByteString senderCertificate; @@ -4060,10 +1344,11 @@ typedef struct { _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/transport_generated_handling.h" ***********************************/ +/**** amalgamated original file "/build/src_generated/open62541/transport_generated_handling.h" ****/ -/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_datatypes.py - * on host mintaka by user pdie at 2021-06-21 11:34:37 */ +/********************************** + * Autogenerated -- do not modify * + **********************************/ @@ -4092,7 +1377,7 @@ UA_MessageType_copy(const UA_MessageType *src, UA_MessageType *dst) { return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_MessageType_deleteMembers(UA_MessageType *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); } @@ -4123,7 +1408,7 @@ UA_ChunkType_copy(const UA_ChunkType *src, UA_ChunkType *dst) { return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_ChunkType_deleteMembers(UA_ChunkType *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); } @@ -4154,7 +1439,7 @@ UA_TcpMessageHeader_copy(const UA_TcpMessageHeader *src, UA_TcpMessageHeader *ds return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_TcpMessageHeader_deleteMembers(UA_TcpMessageHeader *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); } @@ -4185,7 +1470,7 @@ UA_TcpHelloMessage_copy(const UA_TcpHelloMessage *src, UA_TcpHelloMessage *dst) return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_TcpHelloMessage_deleteMembers(UA_TcpHelloMessage *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); } @@ -4216,7 +1501,7 @@ UA_TcpAcknowledgeMessage_copy(const UA_TcpAcknowledgeMessage *src, UA_TcpAcknowl return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_TcpAcknowledgeMessage_deleteMembers(UA_TcpAcknowledgeMessage *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); } @@ -4247,7 +1532,7 @@ UA_TcpErrorMessage_copy(const UA_TcpErrorMessage *src, UA_TcpErrorMessage *dst) return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_TcpErrorMessage_deleteMembers(UA_TcpErrorMessage *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); } @@ -4278,7 +1563,7 @@ UA_AsymmetricAlgorithmSecurityHeader_copy(const UA_AsymmetricAlgorithmSecurityHe return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(UA_AsymmetricAlgorithmSecurityHeader *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); } @@ -4309,7 +1594,7 @@ UA_SequenceHeader_copy(const UA_SequenceHeader *src, UA_SequenceHeader *dst) { return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); } -static UA_INLINE void +UA_DEPRECATED static UA_INLINE void UA_SequenceHeader_deleteMembers(UA_SequenceHeader *p) { UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); } @@ -4331,132 +1616,7 @@ UA_SequenceHeader_delete(UA_SequenceHeader *p) { _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/transport_generated_encoding_binary.h" ***********************************/ - -/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_datatypes.py - * on host mintaka by user pdie at 2021-06-21 11:34:37 */ - - -#ifdef UA_ENABLE_AMALGAMATION -#else -#endif - - - -/* MessageType */ -static UA_INLINE size_t -UA_MessageType_calcSizeBinary(const UA_MessageType *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); -} -static UA_INLINE UA_StatusCode -UA_MessageType_encodeBinary(const UA_MessageType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_MessageType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MessageType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE], NULL); -} - -/* ChunkType */ -static UA_INLINE size_t -UA_ChunkType_calcSizeBinary(const UA_ChunkType *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); -} -static UA_INLINE UA_StatusCode -UA_ChunkType_encodeBinary(const UA_ChunkType *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_ChunkType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ChunkType *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE], NULL); -} - -/* TcpMessageHeader */ -static UA_INLINE size_t -UA_TcpMessageHeader_calcSizeBinary(const UA_TcpMessageHeader *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); -} -static UA_INLINE UA_StatusCode -UA_TcpMessageHeader_encodeBinary(const UA_TcpMessageHeader *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TcpMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TcpMessageHeader *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], NULL); -} - -/* TcpHelloMessage */ -static UA_INLINE size_t -UA_TcpHelloMessage_calcSizeBinary(const UA_TcpHelloMessage *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); -} -static UA_INLINE UA_StatusCode -UA_TcpHelloMessage_encodeBinary(const UA_TcpHelloMessage *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TcpHelloMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TcpHelloMessage *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], NULL); -} - -/* TcpAcknowledgeMessage */ -static UA_INLINE size_t -UA_TcpAcknowledgeMessage_calcSizeBinary(const UA_TcpAcknowledgeMessage *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); -} -static UA_INLINE UA_StatusCode -UA_TcpAcknowledgeMessage_encodeBinary(const UA_TcpAcknowledgeMessage *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TcpAcknowledgeMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TcpAcknowledgeMessage *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], NULL); -} - -/* TcpErrorMessage */ -static UA_INLINE size_t -UA_TcpErrorMessage_calcSizeBinary(const UA_TcpErrorMessage *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); -} -static UA_INLINE UA_StatusCode -UA_TcpErrorMessage_encodeBinary(const UA_TcpErrorMessage *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_TcpErrorMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_TcpErrorMessage *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], NULL); -} - -/* AsymmetricAlgorithmSecurityHeader */ -static UA_INLINE size_t -UA_AsymmetricAlgorithmSecurityHeader_calcSizeBinary(const UA_AsymmetricAlgorithmSecurityHeader *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); -} -static UA_INLINE UA_StatusCode -UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(const UA_AsymmetricAlgorithmSecurityHeader *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_AsymmetricAlgorithmSecurityHeader *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], NULL); -} - -/* SequenceHeader */ -static UA_INLINE size_t -UA_SequenceHeader_calcSizeBinary(const UA_SequenceHeader *src) { - return UA_calcSizeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); -} -static UA_INLINE UA_StatusCode -UA_SequenceHeader_encodeBinary(const UA_SequenceHeader *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { - return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], bufPos, &bufEnd, NULL, NULL); -} -static UA_INLINE UA_StatusCode -UA_SequenceHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SequenceHeader *dst) { - return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL); -} - - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_connection_internal.h" ***********************************/ +/**** amalgamated original file "/src/ua_connection_internal.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -4488,7 +1648,7 @@ void UA_Connection_attachSecureChannel(UA_Connection *connection, _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_securechannel.h" ***********************************/ +/**** amalgamated original file "/src/ua_securechannel.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -4505,8 +1665,34 @@ _UA_END_DECLS _UA_BEGIN_DECLS -#define UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH 12 -#define UA_SECURE_MESSAGE_HEADER_LENGTH 24 +/* The message header of the OPC UA binary protocol is structured as follows: + * + * - MessageType (3 Byte) + * - IsFinal (1 Byte) + * - MessageSize (4 Byte) + * *** UA_SECURECHANNEL_MESSAGEHEADER_LENGTH *** + * - SecureChannelId (4 Byte) + * *** UA_SECURECHANNEL_CHANNELHEADER_LENGTH *** + * - SecurityHeader (4 Byte TokenId for symmetric, otherwise dynamic length) + * - SequenceHeader (8 Byte) + * - SequenceNumber + * - RequestId + */ + +#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8 +#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12 +#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4 +#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8 +#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \ + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \ + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH) +#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH \ + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \ + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH + \ + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH) + +/* Minimum length of a valid message (ERR message with an empty reason) */ +#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16 /* Thread-local variables to force failure modes during testing */ #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS @@ -4523,6 +1709,7 @@ extern UA_StatusCode processSym_seqNumberFailure; typedef struct UA_SessionHeader { SLIST_ENTRY(UA_SessionHeader) next; UA_NodeId authenticationToken; + UA_Boolean serverSession; /* Disambiguate client and server session */ UA_SecureChannel *channel; /* The pointer back to the SecureChannel in the session. */ } UA_SessionHeader; @@ -4532,9 +1719,9 @@ typedef struct UA_Chunk { UA_ByteString bytes; UA_MessageType messageType; UA_ChunkType chunkType; + UA_UInt32 requestId; UA_Boolean copied; /* Do the bytes point to a buffer from the network or was * memory allocated for the chunk separately */ - UA_Boolean decrypted; /* The chunk has been decrypted */ } UA_Chunk; typedef SIMPLEQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue; @@ -4603,9 +1790,17 @@ struct UA_SecureChannel { * buffers is reentrant with the correct processing order. (This has lead to * problems in the client in the past.) */ UA_ChunkQueue completeChunks; /* Received full chunks that have not been - * processed so far */ + * decrypted so far */ + UA_ChunkQueue decryptedChunks; /* Received chunks that were decrypted but + * not processed */ + size_t decryptedChunksCount; + size_t decryptedChunksLength; UA_ByteString incompleteChunk; /* A half-received chunk (TCP is a * streaming protocol) is stored here */ + + UA_CertificateVerification *certificateVerification; + UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel, + const UA_AsymmetricAlgorithmSecurityHeader *asymHeader); }; void UA_SecureChannel_init(UA_SecureChannel *channel, @@ -4698,7 +1893,7 @@ UA_MessageContext_abort(UA_MessageContext *mc); * Receive Message * --------------- */ -typedef void +typedef UA_StatusCode (UA_ProcessMessageCallback)(void *application, UA_SecureChannel *channel, UA_MessageType messageType, UA_UInt32 requestId, UA_ByteString *message); @@ -4759,32 +1954,24 @@ void setBufPos(UA_MessageContext *mc); UA_StatusCode -checkSymHeader(UA_SecureChannel *channel, UA_UInt32 tokenId); - -UA_StatusCode -processSequenceNumberAsym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber); +checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId); UA_StatusCode checkAsymHeader(UA_SecureChannel *channel, const UA_AsymmetricAlgorithmSecurityHeader *asymHeader); void -padChunkAsym(UA_SecureChannel *channel, const UA_ByteString *buf, - size_t securityHeaderLength, UA_Byte **buf_pos); +padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm, + const UA_Byte *start, UA_Byte **pos); UA_StatusCode signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength, UA_ByteString *buf, size_t securityHeaderLength, size_t totalLength); -void -padChunkSym(UA_MessageContext *messageContext, size_t bodyLength); - -UA_StatusCode -signChunkSym(UA_MessageContext *const messageContext, size_t preSigLength); - UA_StatusCode -encryptChunkSym(UA_MessageContext *const messageContext, size_t totalLength); +signAndEncryptSym(UA_MessageContext *messageContext, + size_t preSigLength, size_t totalLength); /** * Log Helper @@ -4855,180 +2042,82 @@ encryptChunkSym(UA_MessageContext *const messageContext, size_t totalLength); _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_workqueue.h" ***********************************/ +/**** amalgamated original file "/src/ua_timer.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2014-2016 (c) Sten Grüner - * Copyright 2015 (c) Chris Iatrou - * Copyright 2015 (c) Nick Goossens - * Copyright 2015 (c) Jörg Schüler-Maroldt - * Copyright 2015-2016 (c) Oleksiy Vasylyev - * Copyright 2016-2017 (c) Florian Palm + * Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2017 (c) Stefan Profanter, fortiss GmbH - * Copyright 2016 (c) Lorenz Haas - * Copyright 2017 (c) Jonas Green */ -#if UA_MULTITHREADING >= 200 -#include <pthread.h> -#endif - _UA_BEGIN_DECLS +/* The timer is protected by its own mutex. The mutex is released before calling + * into the callbacks. So the timer can be modified from the callbacks it is + * executing. Also, the timer mutex can never lead to locking. Because the timer + * mutex will be left without acquiring another mutex. + * + * Obviously, the timer must not be deleted from within one of its + * callbacks. */ + /* Callback where the application is either a client or a server */ typedef void (*UA_ApplicationCallback)(void *application, void *data); -/* Delayed callbacks are executed when all previously enqueue work is finished. - * This is used to free memory that might used by a parallel worker or where the - * current threat has remaining pointers to until the current operation - * finishes. */ -typedef struct UA_DelayedCallback { - SIMPLEQ_ENTRY(UA_DelayedCallback) next; +typedef struct UA_TimerEntry { + struct aa_entry treeEntry; + UA_TimerPolicy timerPolicy; /* Timer policy to handle cycle misses */ + UA_DateTime nextTime; /* The next time when the callback + * is to be executed */ + UA_UInt64 interval; /* Interval in 100ns resolution. If + the interval is zero, the + callback is not repeated and + removed after execution. */ UA_ApplicationCallback callback; void *application; void *data; -} UA_DelayedCallback; - -struct UA_WorkQueue; -typedef struct UA_WorkQueue UA_WorkQueue; -#if UA_MULTITHREADING >= 200 + struct aa_entry idTreeEntry; + UA_UInt64 id; /* Id of the entry */ +} UA_TimerEntry; -/* Workers take out callbacks from the work queue and execute them. - * - * Future Plans: Use work-stealing to load-balance between cores. - * Le, Nhat Minh, et al. "Correct and efficient work-stealing for weak memory - * models." ACM SIGPLAN Notices. Vol. 48. No. 8. ACM, 2013. */ typedef struct { - pthread_t thread; - volatile UA_Boolean running; - UA_WorkQueue *queue; - UA_UInt32 counter; - UA_UInt32 checkpointCounter; /* Counter when the last checkpoint was made - * for the delayed callbacks */ - - /* separate cache lines */ - char padding[64 - sizeof(void*) - sizeof(pthread_t) - - sizeof(UA_UInt32) - sizeof(UA_Boolean)]; -} UA_Worker; - -#endif - -struct UA_WorkQueue { - /* Worker threads and work queue. Without multithreading, work is executed - immediately. */ -#if UA_MULTITHREADING >= 200 - UA_Worker *workers; - size_t workersSize; - - /* Work queue */ - SIMPLEQ_HEAD(, UA_DelayedCallback) dispatchQueue; /* Dispatch queue for the worker threads */ - UA_LOCK_TYPE(dispatchQueue_accessMutex) /* mutex for access to queue */ - pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */ - UA_LOCK_TYPE(dispatchQueue_conditionMutex) /* mutex for access to condition variable */ -#endif - - /* Delayed callbacks - * To be executed after all curretly dispatched works has finished */ - SIMPLEQ_HEAD(, UA_DelayedCallback) delayedCallbacks; -#if UA_MULTITHREADING >= 200 - UA_LOCK_TYPE(delayedCallbacks_accessMutex) - UA_DelayedCallback *delayedCallbacks_checkpoint; - size_t delayedCallbacks_sinceDispatch; /* How many have been added since we - * tried to dispatch callbacks? */ -#endif -}; - -void UA_WorkQueue_init(UA_WorkQueue *wq); - -/* Enqueue a delayed callback. It is executed when all previous work in the - * queue has been finished. The ``cb`` pointer is freed afterwards. ``cb`` can - * have a NULL callback that is not executed. - * - * This method checks internally if existing delayed work can be moved from the - * delayed queue to the worker dispatch queue. */ -void UA_WorkQueue_enqueueDelayed(UA_WorkQueue *wq, UA_DelayedCallback *cb); - -/* Stop the workers, process all enqueued work in the calling thread, clean up - * mutexes etc. */ -void UA_WorkQueue_cleanup(UA_WorkQueue *wq); - -#if UA_MULTITHREADING >= 200 - -/* Spin up a number of worker threads that listen on the work queue */ -UA_StatusCode UA_WorkQueue_start(UA_WorkQueue *wq, size_t workersCount); - -void UA_WorkQueue_stop(UA_WorkQueue *wq); - -/* Enqueue work for the worker threads */ -void UA_WorkQueue_enqueue(UA_WorkQueue *wq, UA_ApplicationCallback cb, - void *application, void *data); - -#else - -/* Process all enqueued delayed work. This is not needed when workers are - * running for the multithreading case. (UA_WorkQueue_cleanup still calls this - * method during cleanup when the workers are shut down.) */ -void UA_WorkQueue_manuallyProcessDelayed(UA_WorkQueue *wq); - + struct aa_head root; /* The root of the time-sorted tree */ + struct aa_head idRoot; /* The root of the id-sorted tree */ + UA_UInt64 idCounter; /* Generate unique identifiers. Identifiers are + * always above zero. */ +#if UA_MULTITHREADING >= 100 + UA_Lock timerMutex; #endif - -_UA_END_DECLS - - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_timer.h" ***********************************/ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2017, 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH - */ - - - -_UA_BEGIN_DECLS - -struct UA_TimerEntry; -typedef struct UA_TimerEntry UA_TimerEntry; - -ZIP_HEAD(UA_TimerZip, UA_TimerEntry); -typedef struct UA_TimerZip UA_TimerZip; - -ZIP_HEAD(UA_TimerIdZip, UA_TimerEntry); -typedef struct UA_TimerIdZip UA_TimerIdZip; - -/* Only for a single thread. Protect by a mutex if required. */ -typedef struct { - UA_TimerZip root; /* The root of the time-sorted zip tree */ - UA_TimerIdZip idRoot; /* The root of the id-sorted zip tree */ - UA_UInt64 idCounter; } UA_Timer; -void UA_Timer_init(UA_Timer *t); +void +UA_Timer_init(UA_Timer *t); UA_StatusCode UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, void *data, UA_DateTime date, UA_UInt64 *callbackId); +/* Add a pre-allocated and pre-filled UA_TimerEntry. This cannot fail. It is + * used, for example, for delayed memory reclamation where the data structure + * begins with a UA_TimerEntry. */ +void +UA_Timer_addTimerEntry(UA_Timer *t, UA_TimerEntry *te, UA_UInt64 *callbackId); + UA_StatusCode UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, void *data, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId); -/* Change the callback interval. If this is called from within the callback. The - * adjustment is made during the next _process call. */ UA_StatusCode -UA_Timer_changeRepeatedCallbackInterval(UA_Timer *t, UA_UInt64 callbackId, - UA_Double interval_ms); +UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy); void UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId); @@ -5046,12 +2135,13 @@ UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic, UA_TimerExecutionCallback executionCallback, void *executionApplication); -void UA_Timer_deleteMembers(UA_Timer *t); +void +UA_Timer_clear(UA_Timer *t); _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_session.h" ***********************************/ +/**** amalgamated original file "/src/server/ua_session.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -5091,23 +2181,41 @@ typedef struct { UA_ApplicationDescription clientDescription; UA_String sessionName; UA_Boolean activated; - void *sessionHandle; // pointer assigned in userland-callback + void *sessionHandle; /* pointer assigned in userland-callback */ UA_NodeId sessionId; UA_UInt32 maxRequestMessageSize; UA_UInt32 maxResponseMessageSize; - UA_Double timeout; // [ms] + UA_Double timeout; /* in ms */ UA_DateTime validTill; UA_ByteString serverNonce; - UA_UInt16 availableContinuationPoints; + + UA_UInt16 availableContinuationPoints; ContinuationPoint *continuationPoints; + + size_t paramsSize; + UA_KeyValuePair *params; + + /* Localization information */ + size_t localeIdsSize; + UA_String *localeIds; + #ifdef UA_ENABLE_SUBSCRIPTIONS - UA_UInt32 lastSubscriptionId; - UA_UInt32 lastSeenSubscriptionId; - LIST_HEAD(UA_ListOfUASubscriptions, UA_Subscription) serverSubscriptions; - SIMPLEQ_HEAD(UA_ListOfQueuedPublishResponses, UA_PublishResponseEntry) responseQueue; - UA_UInt32 numSubscriptions; - UA_UInt32 numPublishReq; - size_t totalRetransmissionQueueSize; /* Retransmissions of all subscriptions */ + /* The queue is ordered according to the priority byte (higher bytes come + * first). When a late subscription finally publishes, then it is pushed to + * the back within the sub-set of subscriptions that has the same priority + * (round-robin scheduling). */ + size_t subscriptionsSize; + TAILQ_HEAD(, UA_Subscription) subscriptions; + + size_t responseQueueSize; + SIMPLEQ_HEAD(, UA_PublishResponseEntry) responseQueue; + + size_t totalRetransmissionQueueSize; /* Retransmissions of all subscriptions */ +#endif + +#ifdef UA_ENABLE_DIAGNOSTICS + UA_SessionSecurityDiagnosticsDataType securityDiagnostics; + UA_SessionDiagnosticsDataType diagnostics; #endif } UA_Session; @@ -5116,7 +2224,7 @@ typedef struct { * ----------------- */ void UA_Session_init(UA_Session *session); -void UA_Session_deleteMembersCleanup(UA_Session *session, UA_Server *server); +void UA_Session_clear(UA_Session *session, UA_Server *server); void UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel); void UA_Session_detachFromSecureChannel(UA_Session *session); UA_StatusCode UA_Session_generateNonce(UA_Session *session); @@ -5131,17 +2239,19 @@ void UA_Session_updateLifetime(UA_Session *session); #ifdef UA_ENABLE_SUBSCRIPTIONS void -UA_Session_addSubscription(UA_Server *server, - UA_Session *session, - UA_Subscription *newSubscription); +UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub); + +/* If releasePublishResponses is true and the last subscription is removed, all + * outstanding PublishResponse are sent with a StatusCode. But we don't do that + * if a Subscription is only detached for modification. */ +void +UA_Session_detachSubscription(UA_Server *server, UA_Session *session, + UA_Subscription *sub, UA_Boolean releasePublishResponses); UA_Subscription * UA_Session_getSubscriptionById(UA_Session *session, UA_UInt32 subscriptionId); -UA_StatusCode -UA_Session_deleteSubscription(UA_Server *server, UA_Session *session, - UA_UInt32 subscriptionId); void UA_Session_queuePublishReq(UA_Session *session, @@ -5161,72 +2271,70 @@ UA_Session_dequeuePublishReq(UA_Session *session); * zero arguments. So we add a dummy argument that is not printed (%.0s is * string of length zero). */ -#define UA_LOG_SESSION_INTERNAL(LOGGER, LEVEL, SESSION, MSG, ...) do { \ - UA_String idString = UA_STRING_NULL; \ - UA_NodeId_print(&(SESSION)->sessionId, &idString); \ +#define UA_LOG_SESSION_INTERNAL(LOGGER, LEVEL, SESSION, MSG, ...) \ + do { \ + int nameLen = (SESSION) ? (int)(SESSION)->sessionName.length : 0; \ + const char *nameStr = (SESSION) ? \ + (const char*)(SESSION)->sessionName.data : NULL; \ + UA_UInt32 chanId = ((SESSION) && (SESSION)->header.channel) ? \ + (SESSION)->header.channel->securityToken.channelId : 0; \ UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SESSION, \ - "Connection %i | SecureChannel %i | Session %.*s | " MSG "%.0s", \ - ((SESSION)->header.channel ? \ - ((SESSION)->header.channel->connection ? \ - (int)((SESSION)->header.channel->connection->sockfd) : 0) : 0), \ - ((SESSION)->header.channel ? \ - (SESSION)->header.channel->securityToken.channelId : 0), \ - (int)idString.length, idString.data, __VA_ARGS__); \ - UA_String_clear(&idString); \ + "SecureChannel %" PRIu32 " | Session \"%.*s\" | " MSG "%.0s", \ + chanId, nameLen, nameStr, __VA_ARGS__); \ } while(0) #if UA_LOGLEVEL <= 100 -#define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) \ +# define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) \ UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, TRACE, SESSION, __VA_ARGS__, "")) #else -#define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) do {} while(0) +# define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) #endif #if UA_LOGLEVEL <= 200 -#define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) \ +# define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) \ UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, DEBUG, SESSION, __VA_ARGS__, "")) #else -#define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) do {} while(0) +# define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) #endif #if UA_LOGLEVEL <= 300 -#define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) \ +# define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) \ UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, INFO, SESSION, __VA_ARGS__, "")) #else -#define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) do {} while(0) +# define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) #endif #if UA_LOGLEVEL <= 400 -#define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) \ +# define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) \ UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, WARNING, SESSION, __VA_ARGS__, "")) #else -#define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) do {} while(0) +# define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) #endif #if UA_LOGLEVEL <= 500 -#define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) \ +# define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) \ UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, ERROR, SESSION, __VA_ARGS__, "")) #else -#define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) do {} while(0) +# define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) #endif #if UA_LOGLEVEL <= 600 -#define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) \ +# define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) \ UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, FATAL, SESSION, __VA_ARGS__, "")) #else -#define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) do {} while(0) +# define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) #endif _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_subscription.h" ***********************************/ +/**** amalgamated original file "/src/server/ua_subscription.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2015-2018, 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2015 (c) Chris Iatrou * Copyright 2015-2016 (c) Sten Grüner * Copyright 2015 (c) Oleksiy Vasylyev @@ -5234,6 +2342,8 @@ _UA_END_DECLS * Copyright 2017 (c) Stefan Profanter, fortiss GmbH * Copyright 2017 (c) Mattias Bornhager * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + * Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + * Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner) */ @@ -5243,18 +2353,7 @@ _UA_BEGIN_DECLS #ifdef UA_ENABLE_SUBSCRIPTIONS -#define UA_BOUNDEDVALUE_SETWBOUNDS(BOUNDS, SRC, DST) { \ - if(SRC > BOUNDS.max) DST = BOUNDS.max; \ - else if(SRC < BOUNDS.min) DST = BOUNDS.min; \ - else DST = SRC; \ - } - -/* Set to the TAILQ_NEXT pointer of a notification, the sentinel that the - * notification was not added to the global queue */ -#define UA_SUBSCRIPTION_QUEUE_SENTINEL ((UA_Notification*)0x01) - -/** - * MonitoredItems create Notifications. Subscriptions collect Notifications from +/* MonitoredItems create Notifications. Subscriptions collect Notifications from * (several) MonitoredItems and publish them to the client. * * Notifications are put into two queues at the same time. One for the @@ -5262,200 +2361,194 @@ _UA_BEGIN_DECLS * space reserved for the MonitoredItem runs full. The second queue is the * "global" queue for all Notifications generated in a Subscription. For * publication, the notifications are taken out of the "global" queue in the - * order of their creation. - */ + * order of their creation. */ /*****************/ -/* MonitoredItem */ +/* Notifications */ /*****************/ -struct UA_MonitoredItem; -typedef struct UA_MonitoredItem UA_MonitoredItem; - -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - -typedef struct UA_EventNotification { - UA_EventFieldList fields; - /* EventFilterResult currently isn't being used - UA_EventFilterResult result; */ -} UA_EventNotification; - -#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS - -typedef enum { - UA_INACTIVE, - UA_ACTIVE, - UA_ACTIVE_HIGHHIGH, - UA_ACTIVE_HIGH, - UA_ACTIVE_LOW, - UA_ACTIVE_LOWLOW -} UA_ActiveState; - -typedef struct { - UA_TwoStateVariableChangeCallback enableStateCallback; - UA_TwoStateVariableChangeCallback ackStateCallback; - UA_Boolean ackedRemoveBranch; - UA_TwoStateVariableChangeCallback confirmStateCallback; - UA_Boolean confirmedRemoveBranch; - UA_TwoStateVariableChangeCallback activeStateCallback; -} UA_ConditionCallbacks; - -/* - * In Alarms and Conditions first implementation, conditionBranchId - * is always equal to NULL NodeId (UA_NODEID_NULL). That ConditionBranch - * represents the current state Condition. The current state is determined - * by the last Event triggered (lastEventId). See Part 9, 5.5.2, BranchId. - */ -typedef struct UA_ConditionBranch { - LIST_ENTRY(UA_ConditionBranch) listEntry; - UA_NodeId conditionBranchId; - UA_ByteString lastEventId; - UA_Boolean isCallerAC; -} UA_ConditionBranch; - -/* - * In Alarms and Conditions first implementation, A Condition - * have only one ConditionBranch entry. - */ -typedef struct UA_Condition { - LIST_ENTRY(UA_Condition) listEntry; - LIST_HEAD(, UA_ConditionBranch) conditionBranchHead; - UA_NodeId conditionId; - UA_UInt16 lastSeverity; - UA_DateTime lastSeveritySourceTimeStamp; - UA_ConditionCallbacks callbacks; - UA_ActiveState lastActiveState; - UA_ActiveState currentActiveState; - UA_Boolean isLimitAlarm; -} UA_Condition; - -/* - * A ConditionSource can have multiple Conditions. - */ -typedef struct UA_ConditionSource { - LIST_ENTRY(UA_ConditionSource) listEntry; - LIST_HEAD(, UA_Condition) conditionHead; - UA_NodeId conditionSourceId; -} UA_ConditionSource; - -#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ - -#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ +/* Set to the TAILQ_NEXT pointer of a notification, the sentinel that the + * notification was not added to the global queue */ +#define UA_SUBSCRIPTION_QUEUE_SENTINEL ((UA_Notification*)0x01) typedef struct UA_Notification { - TAILQ_ENTRY(UA_Notification) listEntry; /* Notification list for the MonitoredItem */ + TAILQ_ENTRY(UA_Notification) localEntry; /* Notification list for the MonitoredItem */ TAILQ_ENTRY(UA_Notification) globalEntry; /* Notification list for the Subscription */ + UA_MonitoredItem *mon; /* Always set */ - UA_MonitoredItem *mon; - - /* See the monitoredItemType of the MonitoredItem */ + /* The event field is used if mon->attributeId is the EventNotifier */ union { + UA_MonitoredItemNotification dataChange; #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - UA_EventNotification event; + UA_EventFieldList event; #endif - UA_DataValue value; } data; -} UA_Notification; -/* Ensure enough space is available; Add notification to the linked lists; - * Increase the counters */ -void UA_Notification_enqueue(UA_Server *server, UA_Subscription *sub, - UA_MonitoredItem *mon, UA_Notification *n); +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + UA_Boolean isOverflowEvent; /* Counted manually */ + UA_EventFilterResult result; +#endif +} UA_Notification; -/* Remove the notification from the MonitoredItem's queue and the Subscriptions - * global queue. Reduce the respective counters. */ -void UA_Notification_dequeue(UA_Server *server, UA_Notification *n); +/* Initializes and sets the sentinel pointers */ +UA_Notification * UA_Notification_new(void); -/* Delete the notification. Must be dequeued first. */ +/* Notifications are always added to the queue of the MonitoredItem. That queue + * can overflow. If Notifications are reported, they are also added to the + * global queue of the Subscription. There they are picked up by the publishing + * callback. + * + * There are two ways Notifications can be put into the global queue of the + * Subscription: They are added because the MonitoringMode of the MonitoredItem + * is "reporting". Or the MonitoringMode is "sampling" and a link is trigered + * that puts the last Notification into the global queue. */ +void UA_Notification_enqueueAndTrigger(UA_Server *server, + UA_Notification *n); + +/* Dequeue and delete the notification */ void UA_Notification_delete(UA_Notification *n); +/* A NotificationMessage contains an array of notifications. + * Sent NotificationMessages are stored for the republish service. */ +typedef struct UA_NotificationMessageEntry { + TAILQ_ENTRY(UA_NotificationMessageEntry) listEntry; + UA_NotificationMessage message; +} UA_NotificationMessageEntry; + +/* Queue Definitions */ typedef TAILQ_HEAD(NotificationQueue, UA_Notification) NotificationQueue; +typedef TAILQ_HEAD(NotificationMessageQueue, UA_NotificationMessageEntry) + NotificationMessageQueue; + +/*****************/ +/* MonitoredItem */ +/*****************/ struct UA_MonitoredItem { - UA_DelayedCallback delayedFreePointers; - LIST_ENTRY(UA_MonitoredItem) listEntry; - UA_Subscription *subscription; /* Local MonitoredItem if the subscription is NULL */ + UA_TimerEntry delayedFreePointers; + LIST_ENTRY(UA_MonitoredItem) listEntry; /* Linked list in the Subscription */ + UA_MonitoredItem *next; /* Linked list of MonitoredItems directly attached + * to a Node. Initialized to ~0 to indicate that the + * MonitoredItem is not added to a node. */ + UA_Subscription *subscription; /* If NULL, then this is a Local MonitoredItem */ UA_UInt32 monitoredItemId; - UA_UInt32 clientHandle; - UA_Boolean registered; /* Was the MonitoredItem registered in Userland with - the callback? */ - /* Settings */ - UA_TimestampsToReturn timestampsToReturn; + /* Status and Settings */ + UA_ReadValueId itemToMonitor; UA_MonitoringMode monitoringMode; - UA_NodeId monitoredNodeId; - UA_UInt32 attributeId; - UA_String indexRange; - UA_Double samplingInterval; // [ms] - UA_Boolean discardOldest; - union { -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - /* If attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER */ - UA_EventFilter eventFilter; -#endif - /* The DataChangeFilter always contains an absolute deadband definition. - * Part 8, §6.2 gives the following formula to test for percentage - * deadbands: - * - * DataChange if (absolute value of (last cached value - current value) - * > (deadbandValue/100.0) * ((high–low) of EURange))) - * - * So we can convert from a percentage to an absolute deadband and keep - * the hot code path simple. - * - * TODO: Store the percentage deadband to recompute when the UARange is - * changed at runtime of the MonitoredItem */ - UA_DataChangeFilter dataChangeFilter; - } filter; - UA_Variant lastValue; // TODO: dataEncoding is hardcoded to UA binary + UA_TimestampsToReturn timestampsToReturn; + UA_Boolean sampleCallbackIsRegistered; + UA_Boolean registered; /* Registered in the server / Subscription */ + UA_DateTime triggeredUntil; /* If the MonitoringMode is SAMPLING, + * triggering the MonitoredItem puts the latest + * Notification into the publishing queue (of + * the Subscription). In addition, the first + * new sample is also published (and not just + * sampled) if it occurs within the duration of + * one publishing cycle after the triggering. */ + + /* If the filter is a UA_DataChangeFilter: The DataChangeFilter always + * contains an absolute deadband definition. Part 8, §6.2 gives the + * following formula to test for percentage deadbands: + * + * DataChange if (absolute value of (last cached value - current value) + * > (deadbandValue/100.0) * ((high–low) of EURange))) + * + * So we can convert from a percentage to an absolute deadband and keep + * the hot code path simple. + * + * TODO: Store the percentage deadband to recompute when the UARange is + * changed at runtime of the MonitoredItem */ + UA_MonitoringParameters parameters; - /* Sample Callback */ + /* Sampling Callback */ UA_UInt64 sampleCallbackId; - UA_ByteString lastSampledValue; - UA_Boolean sampleCallbackIsRegistered; + UA_DataValue lastValue; + + /* Triggering Links */ + size_t triggeringLinksSize; + UA_UInt32 *triggeringLinks; /* Notification Queue */ NotificationQueue queue; - UA_UInt32 maxQueueSize; /* The max number of enqueued notifications (not - * counting overflow events) */ - UA_UInt32 queueSize; - UA_UInt32 eventOverflows; /* Separate counter for the queue. Can at most - * double the queue size */ + size_t queueSize; /* This is the current size. See also the configured + * (maximum) queueSize in the parameters. */ + size_t eventOverflows; /* Separate counter for the queue. Can at most double + * the queue size */ +}; -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - UA_MonitoredItem *next; -#endif +void UA_MonitoredItem_init(UA_MonitoredItem *mon); -#ifdef UA_ENABLE_DA - UA_StatusCode lastStatus; -#endif -}; +void +UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem); -void UA_MonitoredItem_init(UA_MonitoredItem *mon, UA_Subscription *sub); -void UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem); -void UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem); -UA_StatusCode UA_MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon); -void UA_MonitoredItem_unregisterSampleCallback(UA_Server *server, UA_MonitoredItem *mon); +void +UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon); + +void +UA_Server_registerMonitoredItem(UA_Server *server, UA_MonitoredItem *mon); -UA_StatusCode UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event, UA_MonitoredItem *mon); -UA_StatusCode UA_Event_generateEventId(UA_ByteString *generatedId); +/* Register sampling. Either by adding a repeated callback or by adding the + * MonitoredItem to a linked list in the node. */ +UA_StatusCode +UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon); + +void +UA_MonitoredItem_unregisterSampling(UA_Server *server, + UA_MonitoredItem *mon); + +UA_StatusCode +UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon, + UA_MonitoringMode monitoringMode); + +void +UA_MonitoredItem_sampleCallback(UA_Server *server, + UA_MonitoredItem *monitoredItem); + +UA_StatusCode +sampleCallbackWithValue(UA_Server *server, UA_Subscription *sub, + UA_MonitoredItem *mon, UA_DataValue *value); + +UA_StatusCode +UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon, + UA_UInt32 linkId); + +UA_StatusCode +UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon, + UA_UInt32 linkId); + +UA_StatusCode +UA_MonitoredItem_createDataChangeNotification(UA_Server *server, + UA_Subscription *sub, + UA_MonitoredItem *mon, + const UA_DataValue *value); + +UA_StatusCode +UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event, + UA_MonitoredItem *mon); + +UA_StatusCode +UA_Event_generateEventId(UA_ByteString *generatedId); + +void +UA_Event_staticSelectClauseValidation(UA_Server *server, + const UA_EventFilter *eventFilter, + UA_StatusCode *result); + +UA_StatusCode +UA_Event_staticWhereClauseValidation(UA_Server *server, + const UA_ContentFilter *filter, + UA_ContentFilterResult *); /* Remove entries until mon->maxQueueSize is reached. Sets infobits for lost * data if required. */ -UA_StatusCode UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon); - -UA_StatusCode UA_MonitoredItem_removeNodeEventCallback(UA_Server *server, UA_Session *session, - UA_Node *node, void *data); +void +UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon); /****************/ /* Subscription */ /****************/ -typedef struct UA_NotificationMessageEntry { - TAILQ_ENTRY(UA_NotificationMessageEntry) listEntry; - UA_NotificationMessage message; -} UA_NotificationMessageEntry; - /* We use only a subset of the states defined in the standard */ typedef enum { /* UA_SUBSCRIPTIONSTATE_CLOSED */ @@ -5465,12 +2558,18 @@ typedef enum { UA_SUBSCRIPTIONSTATE_KEEPALIVE } UA_SubscriptionState; -typedef TAILQ_HEAD(ListOfNotificationMessages, UA_NotificationMessageEntry) ListOfNotificationMessages; - +/* Subscriptions are managed in a server-wide linked list. If they are attached + * to a Session, then they are additionaly in the per-Session linked-list. A + * subscription is always generated for a Session. But the CloseSession Service + * may keep Subscriptions intact beyond the Session lifetime. They can then be + * re-bound to a new Session with the TransferSubscription Service. */ struct UA_Subscription { - UA_DelayedCallback delayedFreePointers; - LIST_ENTRY(UA_Subscription) listEntry; - UA_Session *session; + UA_TimerEntry delayedFreePointers; + LIST_ENTRY(UA_Subscription) serverListEntry; + /* Ordered according to the priority byte and round-robin scheduling for + * late subscriptions. See ua_session.h. Only set if session != NULL. */ + TAILQ_ENTRY(UA_Subscription) sessionListEntry; + UA_Session *session; /* May be NULL if no session is attached. */ UA_UInt32 subscriptionId; /* Settings */ @@ -5479,17 +2578,19 @@ struct UA_Subscription { UA_Double publishingInterval; /* in ms */ UA_UInt32 notificationsPerPublish; UA_Boolean publishingEnabled; - UA_UInt32 priority; + UA_Byte priority; /* Runtime information */ UA_SubscriptionState state; + UA_StatusCode statusChange; /* If set, a notification is generated and the + * Subscription is deleted within + * UA_Subscription_publish. */ UA_UInt32 nextSequenceNumber; UA_UInt32 currentKeepAliveCount; UA_UInt32 currentLifetimeCount; - /* Publish Callback */ + /* Publish Callback. Registered if id > 0. */ UA_UInt64 publishCallbackId; - UA_Boolean publishCallbackIsRegistered; /* MonitoredItems */ UA_UInt32 lastMonitoredItemId; /* increase the identifiers */ @@ -5497,56 +2598,151 @@ struct UA_Subscription { UA_UInt32 monitoredItemsSize; /* Global list of notifications from the MonitoredItems */ - NotificationQueue notificationQueue; + TAILQ_HEAD(, UA_Notification) notificationQueue; UA_UInt32 notificationQueueSize; /* Total queue size */ UA_UInt32 dataChangeNotifications; UA_UInt32 eventNotifications; - UA_UInt32 statusChangeNotifications; - - /* Notifications to be sent out now (already late). In a regular publish - * callback, all queued notifications are sent out. In a late publish - * response, only the notifications left from the last regular publish - * callback are sent. */ - UA_UInt32 readyNotifications; /* Retransmission Queue */ - ListOfNotificationMessages retransmissionQueue; + NotificationMessageQueue retransmissionQueue; size_t retransmissionQueueSize; + + /* Statistics for the server diagnostics. The fields are defined according + * to the SubscriptionDiagnosticsDataType (Part 5, §12.15). */ +#ifdef UA_ENABLE_DIAGNOSTICS + UA_UInt32 modifyCount; + UA_UInt32 enableCount; + UA_UInt32 disableCount; + UA_UInt32 republishRequestCount; + UA_UInt32 republishMessageCount; + UA_UInt32 transferRequestCount; + UA_UInt32 transferredToAltClientCount; + UA_UInt32 transferredToSameClientCount; + UA_UInt32 publishRequestCount; + UA_UInt32 dataChangeNotificationsCount; + UA_UInt32 eventNotificationsCount; + UA_UInt32 notificationsCount; + UA_UInt32 latePublishRequestCount; + UA_UInt32 discardedMessageCount; + UA_UInt32 monitoringQueueOverflowCount; + UA_UInt32 eventQueueOverFlowCount; +#endif }; -UA_Subscription * UA_Subscription_new(UA_Session *session, UA_UInt32 subscriptionId); -void UA_Subscription_deleteMembers(UA_Server *server, UA_Subscription *sub); -UA_StatusCode Subscription_registerPublishCallback(UA_Server *server, UA_Subscription *sub); -void Subscription_unregisterPublishCallback(UA_Server *server, UA_Subscription *sub); -void UA_Subscription_addMonitoredItem(UA_Server *server, UA_Subscription *sub, UA_MonitoredItem *newMon); -UA_MonitoredItem * UA_Subscription_getMonitoredItem(UA_Subscription *sub, UA_UInt32 monitoredItemId); +UA_Subscription * UA_Subscription_new(void); + +void +UA_Subscription_delete(UA_Server *server, UA_Subscription *sub); UA_StatusCode -UA_Subscription_deleteMonitoredItem(UA_Server *server, UA_Subscription *sub, - UA_UInt32 monitoredItemId); +Subscription_registerPublishCallback(UA_Server *server, + UA_Subscription *sub); -void UA_Subscription_publish(UA_Server *server, UA_Subscription *sub); -UA_StatusCode UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub, - UA_UInt32 sequenceNumber); -void UA_Subscription_answerPublishRequestsNoSubscription(UA_Server *server, UA_Session *session); -UA_Boolean UA_Subscription_reachedPublishReqLimit(UA_Server *server, UA_Session *session); +void +Subscription_unregisterPublishCallback(UA_Server *server, + UA_Subscription *sub); -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS +UA_MonitoredItem * +UA_Subscription_getMonitoredItem(UA_Subscription *sub, + UA_UInt32 monitoredItemId); + +void +UA_Subscription_publish(UA_Server *server, UA_Subscription *sub); -/* Only for unit testing */ UA_StatusCode -UA_Server_evaluateWhereClauseContentFilter( - UA_Server *server, - const UA_NodeId *eventNode, - const UA_ContentFilter *contentFilter); -#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ +UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub, + UA_UInt32 sequenceNumber); + +UA_Boolean +UA_Session_reachedPublishReqLimit(UA_Server *server, UA_Session *session); + +/* Forward declaration for A&C used in ua_server_internal.h" */ +struct UA_ConditionSource; +typedef struct UA_ConditionSource UA_ConditionSource; + +/***********/ +/* Helpers */ +/***********/ + +/* Evaluate content filter, Only for unit testing */ +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS +UA_StatusCode +UA_Server_evaluateWhereClauseContentFilter(UA_Server *server, UA_Session *session, + const UA_NodeId *eventNode, + const UA_ContentFilter *contentFilter, + UA_ContentFilterResult *contentFilterResult); +#endif + +/* Setting an integer value within bounds */ +#define UA_BOUNDEDVALUE_SETWBOUNDS(BOUNDS, SRC, DST) { \ + if(SRC > BOUNDS.max) DST = BOUNDS.max; \ + else if(SRC < BOUNDS.min) DST = BOUNDS.min; \ + else DST = SRC; \ + } + +/* Logging + * See a description of the tricks used in ua_session.h */ +#define UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, LEVEL, SUB, MSG, ...) \ + do { \ + if((SUB) && (SUB)->session) { \ + UA_LOG_##LEVEL##_SESSION(LOGGER, (SUB)->session, \ + "Subscription %" PRIu32 " | " MSG "%.0s", \ + (SUB)->subscriptionId, __VA_ARGS__); \ + } else { \ + UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SERVER, \ + "Subscription %" PRIu32 " | " MSG "%.0s", \ + (SUB) ? (SUB)->subscriptionId : 0, __VA_ARGS__); \ + } \ + } while(0) + +#if UA_LOGLEVEL <= 100 +# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, TRACE, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 200 +# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, DEBUG, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 300 +# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, INFO, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 400 +# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, WARNING, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 500 +# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, ERROR, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 600 +# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, FATAL, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif #endif /* UA_ENABLE_SUBSCRIPTIONS */ _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_networkmessage.h" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -5568,16 +2764,17 @@ typedef struct { /* FieldEncoding Enum */ typedef enum { - UA_FIELDENCODING_VARIANT = 0, + UA_FIELDENCODING_VARIANT = 0, UA_FIELDENCODING_RAWDATA = 1, - UA_FIELDENCODING_DATAVALUE = 2 + UA_FIELDENCODING_DATAVALUE = 2, + UA_FIELDENCODING_UNKNOWN = 3 } UA_FieldEncoding; /* DataSetMessage Type */ typedef enum { UA_DATASETMESSAGE_DATAKEYFRAME = 0, UA_DATASETMESSAGE_DATADELTAFRAME = 1, - UA_DATASETMESSAGE_EVENT = 2, + UA_DATASETMESSAGE_EVENT = 2, UA_DATASETMESSAGE_KEEPALIVE = 3 } UA_DataSetMessageType; @@ -5600,52 +2797,6 @@ typedef struct { UA_UInt32 configVersionMinorVersion; } UA_DataSetMessageHeader; -UA_StatusCode -UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, - UA_Byte **bufPos, const UA_Byte *bufEnd); - -UA_StatusCode -UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, - UA_DataSetMessageHeader* dst); - -size_t -UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p); - -/**********************************************/ -/* Network Message Offsets */ -/**********************************************/ - -/* Offsets for buffered messages in the PubSub fast path. */ -typedef enum { - UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER, - UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER, - UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS, - UA_PUBSUB_OFFSETTYPE_TIMESTAMP, /* source pointer */ - UA_PUBSUB_OFFSETTYPE_TIMESTAMP_NOW, /* no source */ - UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE, - UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT, - UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW - /* Add more offset types as needed */ -} UA_NetworkMessageOffsetType; - -typedef struct { - UA_NetworkMessageOffsetType contentType; - union { - union { - UA_DataValue *value; - size_t valueBinarySize; - } value; - UA_DateTime *timestamp; - } offsetData; - size_t offset; -} UA_NetworkMessageOffset; - -typedef struct { - UA_ByteString buffer; /* The precomputed message buffer */ - UA_NetworkMessageOffset *offsets; /* Offsets for changes in the message buffer */ - size_t offsetsSize; -} UA_NetworkMessageOffsetBuffer; - /** * DataSetMessage * ^^^^^^^^^^^^^^ */ @@ -5653,6 +2804,7 @@ typedef struct { typedef struct { UA_UInt16 fieldCount; UA_DataValue* dataSetFields; + UA_ByteString rawFields; /* Json keys for the dataSetFields: TODO: own dataSetMessageType for json? */ UA_String* fieldNames; } UA_DataSetMessage_DataKeyFrameData; @@ -5675,20 +2827,6 @@ typedef struct { } data; } UA_DataSetMessage; -UA_StatusCode -UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos, - const UA_Byte *bufEnd); - -UA_StatusCode -UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, - UA_DataSetMessage* dst); - -size_t -UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer, - size_t currentOffset); - -void UA_DataSetMessage_free(const UA_DataSetMessage* p); - typedef struct { UA_UInt16* sizes; UA_DataSetMessage* dataSetMessages; @@ -5731,7 +2869,6 @@ typedef struct { UA_Boolean securityFooterEnabled; UA_Boolean forceKeyReset; UA_UInt32 securityTokenId; // spec: IntegerId - UA_Byte nonceLength; UA_ByteString messageNonce; UA_UInt16 securityFooterSize; } UA_NetworkMessageSecurityHeader; @@ -5782,27 +2919,151 @@ typedef struct { } payload; UA_ByteString securityFooter; - UA_ByteString signature; } UA_NetworkMessage; +/**********************************************/ +/* Network Message Offsets */ +/**********************************************/ + +/* Offsets for buffered messages in the PubSub fast path. */ +typedef enum { + UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER, + UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER, + UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING, + UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS, + UA_PUBSUB_OFFSETTYPE_TIMESTAMP, /* source pointer */ + UA_PUBSUB_OFFSETTYPE_TIMESTAMP_NOW, /* no source */ + UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE, + UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT, + UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW, + /* For subscriber RT */ + UA_PUBSUB_OFFSETTYPE_PUBLISHERID, + UA_PUBSUB_OFFSETTYPE_WRITERGROUPID, + UA_PUBSUB_OFFSETTYPE_DATASETWRITERID + /* Add more offset types as needed */ +} UA_NetworkMessageOffsetType; + +typedef struct { + UA_NetworkMessageOffsetType contentType; + union { + struct { + UA_DataValue *value; + size_t valueBinarySize; + } value; + UA_DateTime *timestamp; + } offsetData; + size_t offset; +} UA_NetworkMessageOffset; + +typedef struct { + UA_ByteString buffer; /* The precomputed message buffer */ + UA_NetworkMessageOffset *offsets; /* Offsets for changes in the message buffer */ + size_t offsetsSize; + UA_Boolean RTsubscriberEnabled; /* Addtional offsets computation like publisherId, WGId if this bool enabled */ + UA_NetworkMessage *nm; /* The precomputed NetworkMessage for subscriber */ + size_t rawMessageLength; +} UA_NetworkMessageOffsetBuffer; + +/** + * DataSetMessage + * ^^^^^^^^^^^^^^ */ + +UA_StatusCode +UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +UA_StatusCode +UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_DataSetMessageHeader* dst); + +size_t +UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p); + +UA_StatusCode +UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd); + +UA_StatusCode +UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_DataSetMessage* dst, UA_UInt16 dsmSize); + +size_t +UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer, + size_t currentOffset); + +void UA_DataSetMessage_clear(const UA_DataSetMessage* p); + +/** + * NetworkMessage + * ^^^^^^^^^^^^^^ */ + UA_StatusCode UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer); UA_StatusCode +UA_NetworkMessage_updateBufferedNwMessage(UA_NetworkMessageOffsetBuffer *buffer, + const UA_ByteString *src, size_t *bufferPosition); + + +/** + * NetworkMessage Encoding + * ^^^^^^^^^^^^^^^^^^^^^^^ */ + +/* If dataToEncryptStart not-NULL, then it will be set to the start-position of + * the payload in the buffer. */ +UA_StatusCode UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd, + UA_Byte **dataToEncryptStart); + +UA_StatusCode +UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +UA_StatusCode +UA_NetworkMessage_encodePayload(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +UA_StatusCode +UA_NetworkMessage_encodeFooters(const UA_NetworkMessage* src, UA_Byte **bufPos, const UA_Byte *bufEnd); +/** + * NetworkMessage Decoding + * ^^^^^^^^^^^^^^^^^^^^^^^ */ + +UA_StatusCode +UA_NetworkMessage_decodeHeaders(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + +UA_StatusCode +UA_NetworkMessage_decodePayload(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + +UA_StatusCode +UA_NetworkMessage_decodeFooters(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + UA_StatusCode UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkMessage* dst); + +UA_StatusCode +UA_NetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + size_t -UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer); +UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, + UA_NetworkMessageOffsetBuffer *offsetBuffer); -void -UA_NetworkMessage_deleteMembers(UA_NetworkMessage* p); +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION -#define UA_NetworkMessage_clear(p) UA_NetworkMessage_deleteMembers(p) +UA_StatusCode +UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode, + UA_PubSubSecurityPolicy *policy, void *policyContext, + UA_Byte *messageStart, UA_Byte *encryptStart, + UA_Byte *sigStart); +#endif + +void +UA_NetworkMessage_clear(UA_NetworkMessage* p); void UA_NetworkMessage_delete(UA_NetworkMessage* p); @@ -5827,7 +3088,7 @@ UA_StatusCode UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, const UA_Byte _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub.h" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -5835,29 +3096,31 @@ _UA_END_DECLS * * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner) * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes) */ +/* The public configuration structs are defined in include/ua_plugin_pubsub.h */ + _UA_BEGIN_DECLS -#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ +#ifdef UA_ENABLE_PUBSUB -/* forward declarations */ struct UA_WriterGroup; typedef struct UA_WriterGroup UA_WriterGroup; -/* Declaration for ReaderGroup */ struct UA_ReaderGroup; typedef struct UA_ReaderGroup UA_ReaderGroup; -/* The configuration structs (public part of PubSub entities) are defined in include/ua_plugin_pubsub.h */ - /**********************************************/ /* PublishedDataSet */ /**********************************************/ -typedef struct UA_PublishedDataSet{ + +typedef struct UA_PublishedDataSet { UA_PublishedDataSetConfig config; UA_DataSetMetaDataType dataSetMetaData; TAILQ_HEAD(UA_ListOfDataSetField, UA_DataSetField) fields; @@ -5866,57 +3129,78 @@ typedef struct UA_PublishedDataSet{ UA_UInt16 promotedFieldsCount; UA_UInt16 configurationFreezeCounter; TAILQ_ENTRY(UA_PublishedDataSet) listEntry; + UA_Boolean configurationFrozen; } UA_PublishedDataSet; UA_StatusCode -UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src, UA_PublishedDataSetConfig *dst); +UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src, + UA_PublishedDataSetConfig *dst); + UA_PublishedDataSet * UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier); + void -UA_PublishedDataSet_clear(UA_Server *server, UA_PublishedDataSet *publishedDataSet); +UA_PublishedDataSet_clear(UA_Server *server, + UA_PublishedDataSet *publishedDataSet); /**********************************************/ /* Connection */ /**********************************************/ -//the connection config (public part of connection) object is defined in include/ua_plugin_pubsub.h -typedef struct UA_PubSubConnection{ + +typedef struct UA_PubSubConnection { + UA_PubSubComponentEnumType componentType; UA_PubSubConnectionConfig *config; - //internal fields UA_PubSubChannel *channel; UA_NodeId identifier; LIST_HEAD(UA_ListOfWriterGroup, UA_WriterGroup) writerGroups; + size_t writerGroupsSize; LIST_HEAD(UA_ListOfPubSubReaderGroup, UA_ReaderGroup) readerGroups; size_t readerGroupsSize; TAILQ_ENTRY(UA_PubSubConnection) listEntry; UA_UInt16 configurationFreezeCounter; + UA_Boolean isRegistered; /* Subscriber requires connection channel regist */ + UA_Boolean configurationFrozen; } UA_PubSubConnection; UA_StatusCode -UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src, UA_PubSubConnectionConfig *dst); +UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src, + UA_PubSubConnectionConfig *dst); + UA_PubSubConnection * -UA_PubSubConnection_findConnectionbyId(UA_Server *server, UA_NodeId connectionIdentifier); +UA_PubSubConnection_findConnectionbyId(UA_Server *server, + UA_NodeId connectionIdentifier); + void UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig); + void UA_PubSubConnection_clear(UA_Server *server, UA_PubSubConnection *connection); + /* Register channel for given connectionIdentifier */ UA_StatusCode UA_PubSubConnection_regist(UA_Server *server, UA_NodeId *connectionIdentifier); +/* Process Network Message for a ReaderGroup. But we the ReaderGroup needs to be + * identified first. */ +UA_StatusCode +UA_Server_processNetworkMessage(UA_Server *server, + UA_PubSubConnection *connection, + UA_NetworkMessage *msg); + /**********************************************/ /* DataSetWriter */ /**********************************************/ #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES -typedef struct UA_DataSetWriterSample{ +typedef struct UA_DataSetWriterSample { UA_Boolean valueChanged; UA_DataValue value; } UA_DataSetWriterSample; #endif -typedef struct UA_DataSetWriter{ +typedef struct UA_DataSetWriter { + UA_PubSubComponentEnumType componentType; UA_DataSetWriterConfig config; - //internal fields LIST_ENTRY(UA_DataSetWriter) listEntry; UA_NodeId identifier; UA_NodeId linkedWriterGroup; @@ -5924,27 +3208,41 @@ typedef struct UA_DataSetWriter{ UA_ConfigurationVersionDataType connectedDataSetVersion; UA_PubSubState state; #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES - UA_UInt16 deltaFrameCounter; //actual count of sent deltaFrames + UA_UInt16 deltaFrameCounter; /* count of sent deltaFrames */ size_t lastSamplesCount; UA_DataSetWriterSample *lastSamples; #endif UA_UInt16 actualDataSetMessageSequenceCount; + UA_Boolean configurationFrozen; } UA_DataSetWriter; UA_StatusCode -UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src, UA_DataSetWriterConfig *dst); +UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src, + UA_DataSetWriterConfig *dst); + UA_DataSetWriter * UA_DataSetWriter_findDSWbyId(UA_Server *server, UA_NodeId identifier); + UA_StatusCode -UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, UA_DataSetWriter *dataSetWriter); +UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_DataSetWriter *dataSetWriter); + +UA_StatusCode +UA_DataSetWriter_generateDataSetMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, + UA_DataSetWriter *dataSetWriter); + +UA_StatusCode +UA_DataSetWriter_remove(UA_Server *server, UA_WriterGroup *linkedWriterGroup, + UA_DataSetWriter *dataSetWriter); /**********************************************/ /* WriterGroup */ /**********************************************/ -struct UA_WriterGroup{ +struct UA_WriterGroup { + UA_PubSubComponentEnumType componentType; UA_WriterGroupConfig config; - //internal fields LIST_ENTRY(UA_WriterGroup) listEntry; UA_NodeId identifier; UA_PubSubConnection *linkedConnection; @@ -5955,33 +3253,45 @@ struct UA_WriterGroup{ UA_PubSubState state; UA_NetworkMessageOffsetBuffer bufferedMessage; UA_UInt16 sequenceNumber; /* Increased after every succressuly sent message */ + UA_Boolean configurationFrozen; + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_UInt32 securityTokenId; + UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */ + void *securityPolicyContext; +#endif }; UA_StatusCode -UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src, UA_WriterGroupConfig *dst); +UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src, + UA_WriterGroupConfig *dst); + UA_WriterGroup * UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier); + UA_StatusCode -UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, UA_WriterGroup *writerGroup); +UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_WriterGroup *writerGroup); /**********************************************/ /* DataSetField */ /**********************************************/ -typedef struct UA_DataSetField{ +typedef struct UA_DataSetField { UA_DataSetFieldConfig config; - //internal fields TAILQ_ENTRY(UA_DataSetField) listEntry; UA_NodeId identifier; - UA_NodeId publishedDataSet; //ref to parent pds - UA_FieldMetaData fieldMetaData; + UA_NodeId publishedDataSet; /* parent pds */ + UA_FieldMetaData fieldMetaData; /* contains the dataSetFieldId */ UA_UInt64 sampleCallbackId; UA_Boolean sampleCallbackIsRegistered; - + UA_Boolean configurationFrozen; } UA_DataSetField; UA_StatusCode -UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, UA_DataSetFieldConfig *dst); +UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, + UA_DataSetFieldConfig *dst); + UA_DataSetField * UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier); @@ -5989,43 +3299,85 @@ UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier); /* DataSetReader */ /**********************************************/ -/* SubscribedDataSetDataType Definition */ -typedef enum { - UA_PUBSUB_SDS_TARGET, - UA_PUBSUB_SDS_MIRROR -}UA_SubscribedDataSetEnumType; - /* DataSetReader Type definition */ typedef struct UA_DataSetReader { + UA_PubSubComponentEnumType componentType; UA_DataSetReaderConfig config; - /* implementation defined fields */ UA_NodeId identifier; UA_NodeId linkedReaderGroup; LIST_ENTRY(UA_DataSetReader) listEntry; - UA_SubscribedDataSetEnumType subscribedDataSetType; - UA_TargetVariablesDataType subscribedDataSetTarget; - /* To Do UA_SubscribedDataSetMirrorDataType subscribedDataSetMirror */ -}UA_DataSetReader; -/* Delete DataSetReader */ -void UA_DataSetReader_delete(UA_Server *server, UA_DataSetReader *dataSetReader); + UA_PubSubState state; /* non std */ + UA_Boolean configurationFrozen; + UA_NetworkMessageOffsetBuffer bufferedMessage; + +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* MessageReceiveTimeout handling */ + UA_ServerCallback msgRcvTimeoutTimerCallback; + UA_UInt64 msgRcvTimeoutTimerId; + UA_Boolean msgRcvTimeoutTimerRunning; +#endif +} UA_DataSetReader; /* Process Network Message using DataSetReader */ -void UA_Server_DataSetReader_process(UA_Server *server, UA_DataSetReader *dataSetReader, UA_DataSetMessage* dataSetMsg); +void +UA_DataSetReader_process(UA_Server *server, + UA_ReaderGroup *readerGroup, + UA_DataSetReader *dataSetReader, + UA_DataSetMessage *dataSetMsg); /* Copy the configuration of DataSetReader */ -UA_StatusCode UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src, UA_DataSetReaderConfig *dst); +UA_StatusCode UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src, + UA_DataSetReaderConfig *dst); + +/* Clear the configuration of a DataSetReader */ +void UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg); + +/* Copy the configuration of Target Variables */ +UA_StatusCode UA_TargetVariables_copy(const UA_TargetVariables *src, + UA_TargetVariables *dst); + +/* Clear the Target Variables configuration */ +void UA_TargetVariables_clear(UA_TargetVariables *subscribedDataSetTarget); + +/* Copy the configuration of Field Target Variables */ +UA_StatusCode UA_FieldTargetVariable_copy(const UA_FieldTargetVariable *src, + UA_FieldTargetVariable *dst); -/* Add TargetVariables */ UA_StatusCode -UA_Server_DataSetReader_addTargetVariables(UA_Server* server, UA_NodeId* parentNode, UA_NodeId dataSetReaderIdentifier, UA_SubscribedDataSetEnumType sdsType); +UA_DataSetReader_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_DataSetReader *dataSetReader); + +#ifdef UA_ENABLE_PUBSUB_MONITORING +/* Check if DataSetReader has a message receive timeout */ +void +UA_DataSetReader_checkMessageReceiveTimeout(UA_Server *server, + UA_DataSetReader *dataSetReader); + +/* DataSetReader MessageReceiveTimeout callback for generic PubSub component + * timeout handling */ +void +UA_DataSetReader_handleMessageReceiveTimeout(UA_Server *server, + void *dataSetReader); +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + +UA_StatusCode +UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection, + UA_DataSetReader *dataSetReader, + UA_DataSetMessage *dsm, UA_UInt16 *writerId, + UA_Byte dsmCount, UA_NetworkMessage *nm); + +UA_StatusCode +UA_DataSetReader_generateDataSetMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, + UA_DataSetReader *dataSetReader); /**********************************************/ /* ReaderGroup */ /**********************************************/ -/* ReaderGroup Type Definition*/ struct UA_ReaderGroup { + UA_PubSubComponentEnumType componentType; UA_ReaderGroupConfig config; UA_NodeId identifier; UA_NodeId linkedConnection; @@ -6034,24 +3386,31 @@ struct UA_ReaderGroup { /* for simplified information access */ UA_UInt32 readersCount; UA_UInt64 subscribeCallbackId; - UA_Boolean subscribeCallbackIsRegistered; -}; - -/* Delete ReaderGroup */ -void UA_Server_ReaderGroup_delete(UA_Server *server, UA_ReaderGroup *readerGroup); + UA_PubSubState state; + UA_Boolean configurationFrozen; -/* Copy configuration of ReaderGroup */ -UA_StatusCode -UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src, UA_ReaderGroupConfig *dst); +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_UInt32 securityTokenId; + UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */ + void *securityPolicyContext; +#endif +}; -/* Process Network Message */ UA_StatusCode -UA_Server_processNetworkMessage(UA_Server *server, UA_NetworkMessage* pMsg, UA_PubSubConnection *pConnection); +UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src, + UA_ReaderGroupConfig *dst); /* Prototypes for internal util functions - some functions maybe removed later - *(currently moved from public to internal)*/ -UA_ReaderGroup *UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier); -UA_DataSetReader *UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier); + * (currently moved from public to internal) */ +UA_ReaderGroup * +UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier); + +UA_DataSetReader * +UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier); + +UA_StatusCode +UA_ReaderGroup_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_ReaderGroup *readerGroup); /*********************************************************/ /* PublishValues handling */ @@ -6059,6 +3418,7 @@ UA_DataSetReader *UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identi UA_StatusCode UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup); + void UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup); @@ -6068,15 +3428,46 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup); UA_StatusCode UA_ReaderGroup_addSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup); + +void +UA_ReaderGroup_removeSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup); + void UA_ReaderGroup_subscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup); +/*********************************************************/ +/* Reading Message handling */ +/*********************************************************/ + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION +UA_StatusCode +verifyAndDecrypt(const UA_Logger *logger, UA_ByteString *buffer, + const size_t *currentPosition, const UA_NetworkMessage *nm, + UA_Boolean doValidate, UA_Boolean doDecrypt, + void *channelContext, UA_PubSubSecurityPolicy *securityPolicy); + +UA_StatusCode +verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString *buffer, + size_t *currentPosition, UA_NetworkMessage *nm, + UA_ReaderGroup *readerGroup); +#endif + +/* Takes a value (and not a pointer) to the buffer. The original buffer is + const. Internally we may adjust the length during decryption. */ +UA_StatusCode +decodeNetworkMessage(UA_Server *server, UA_ByteString *buffer, size_t *pos, + UA_NetworkMessage *nm, UA_PubSubConnection *connection); + +UA_StatusCode +receiveBufferedNetworkMessage(UA_Server *server, UA_ReaderGroup *readerGroup, + UA_PubSubConnection *connection); + #endif /* UA_ENABLE_PUBSUB */ _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_manager.h" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_manager.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -6092,19 +3483,30 @@ _UA_BEGIN_DECLS #ifdef UA_ENABLE_PUBSUB /* conditional compilation */ -typedef struct UA_PubSubManager{ - //Connections and PublishedDataSets can exist alone (own lifecycle) -> top level components +typedef struct UA_PubSubManager { + /* Connections and PublishedDataSets can exist alone (own lifecycle) -> top + * level components */ size_t connectionsSize; TAILQ_HEAD(UA_ListOfPubSubConnection, UA_PubSubConnection) connections; + size_t publishedDataSetsSize; TAILQ_HEAD(UA_ListOfPublishedDataSet, UA_PublishedDataSet) publishedDataSets; + +#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL + UA_UInt32 uniqueIdCount; +#endif } UA_PubSubManager; void UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager); +#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL void -UA_PubSubManager_generateUniqueNodeId(UA_Server *server, UA_NodeId *nodeId); +UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId); +#endif + +UA_Guid +UA_PubSubManager_generateUniqueGuid(UA_Server *server); UA_UInt32 UA_PubSubConfigurationVersionTimeDifference(void); @@ -6114,19 +3516,32 @@ UA_PubSubConfigurationVersionTimeDifference(void); /***********************************/ UA_StatusCode UA_PubSubManager_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, - void *data, UA_Double interval_ms, UA_UInt64 *callbackId); + void *data, UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId); UA_StatusCode -UA_PubSubManager_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, - UA_Double interval_ms); +UA_PubSubManager_changeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy); void UA_PubSubManager_removeRepeatedPubSubCallback(UA_Server *server, UA_UInt64 callbackId); +/*************************************************/ +/* PubSub component monitoring */ +/*************************************************/ + +#ifdef UA_ENABLE_PUBSUB_MONITORING + +UA_StatusCode +UA_PubSubManager_setDefaultMonitoringCallbacks(UA_PubSubMonitoringInterface *monitoringInterface); + +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + #endif /* UA_ENABLE_PUBSUB */ _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_ns0.h" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -6180,13 +3595,16 @@ addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReade UA_StatusCode removeDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader); +UA_StatusCode +removeReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup); + #endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */ _UA_END_DECLS #endif /* UA_PUBSUB_NS0_H_ */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_async.h" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_async.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -6247,7 +3665,7 @@ typedef struct { /* Operations for the workers. The queues are all FIFO: Put in at the tail, * take out at the head.*/ - UA_LOCK_TYPE(queueLock) + UA_Lock queueLock; UA_AsyncOperationQueue newQueue; /* New operations for the workers */ UA_AsyncOperationQueue dispatchedQueue; /* Operations taken by a worker. When a result is * returned, we search for the op here to see if it @@ -6301,7 +3719,7 @@ UA_FUNC_ATTR_WARN_UNUSED_RESULT; _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_internal.h" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_internal.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -6358,13 +3776,13 @@ typedef enum { } UA_DiagnosticEvent; typedef struct channel_entry { - UA_DelayedCallback cleanupCallback; + UA_TimerEntry cleanupCallback; TAILQ_ENTRY(channel_entry) pointers; UA_SecureChannel channel; } channel_entry; typedef struct session_list_entry { - UA_DelayedCallback cleanupCallback; + UA_TimerEntry cleanupCallback; LIST_ENTRY(session_list_entry) pointers; UA_Session session; } session_list_entry; @@ -6395,6 +3813,7 @@ struct UA_Server { /* Session Management */ LIST_HEAD(session_list, session_list_entry) sessions; UA_UInt32 sessionCount; + UA_UInt32 activeSessionCount; UA_Session adminSession; /* Local access to the services (for startup and * maintenance) uses this Session with all possible * access rights (Session Id: 1) */ @@ -6406,9 +3825,6 @@ struct UA_Server { /* Callbacks with a repetition interval */ UA_Timer timer; - /* WorkQueue and worker threads */ - UA_WorkQueue workQueue; - /* For bootstrapping, omit some consistency checks, creating a reference to * the parent and member instantiation */ UA_Boolean bootstrapNS0; @@ -6418,19 +3834,22 @@ struct UA_Server { UA_DiscoveryManager discoveryManager; #endif - /* DataChange Subscriptions */ + /* Subscriptions */ #ifdef UA_ENABLE_SUBSCRIPTIONS - /* Num active subscriptions */ - UA_UInt32 numSubscriptions; - /* Num active monitored items */ - UA_UInt32 numMonitoredItems; + size_t subscriptionsSize; /* Number of active subscriptions */ + size_t monitoredItemsSize; /* Number of active monitored items */ + LIST_HEAD(, UA_Subscription) subscriptions; /* All subscriptions in the + * server. They may be detached + * from a session. */ + UA_UInt32 lastSubscriptionId; /* To generate unique SubscriptionIds */ + /* To be cast to UA_LocalMonitoredItem to get the callback and context */ - LIST_HEAD(LocalMonitoredItems, UA_MonitoredItem) localMonitoredItems; + LIST_HEAD(, UA_MonitoredItem) localMonitoredItems; UA_UInt32 lastLocalMonitoredItemId; -#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS - LIST_HEAD(conditionSourcelisthead, UA_ConditionSource) headConditionSource; -#endif//UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS +# ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + LIST_HEAD(, UA_ConditionSource) conditionSources; +# endif #endif @@ -6440,19 +3859,31 @@ struct UA_Server { #endif #if UA_MULTITHREADING >= 100 - UA_LOCK_TYPE(networkMutex) - UA_LOCK_TYPE(serviceMutex) + UA_Lock networkMutex; + UA_Lock serviceMutex; #endif /* Statistics */ - UA_ServerStatistics serverStats; + UA_NetworkStatistics networkStatistics; + UA_SecureChannelStatistics secureChannelStatistics; + UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary; }; +/***********************/ +/* References Handling */ +/***********************/ + +extern const struct aa_head refNameTree; + +const UA_ReferenceTarget * +UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk, + const UA_ExpandedNodeId *targetId); + /**************************/ /* SecureChannel Handling */ /**************************/ -/* Remove a all securechannels */ +/* Remove all securechannels */ void UA_Server_deleteSecureChannels(UA_Server *server); @@ -6465,17 +3896,24 @@ UA_StatusCode UA_Server_createSecureChannel(UA_Server *server, UA_Connection *connection); UA_StatusCode -UA_Server_configSecureChannel(UA_Server *server, UA_SecureChannel *channel, +UA_Server_configSecureChannel(void *application, UA_SecureChannel *channel, const UA_AsymmetricAlgorithmSecurityHeader *asymHeader); UA_StatusCode -sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 requestHandle, - const UA_DataType *responseType, UA_StatusCode statusCode); +sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, + UA_UInt32 requestHandle, UA_StatusCode statusCode); void UA_Server_closeSecureChannel(UA_Server *server, UA_SecureChannel *channel, UA_DiagnosticEvent event); +/* Gets the a pointer to the context of a security policy supported by the + * server matched by the security policy uri. */ +UA_SecurityPolicy * +getSecurityPolicyByUri(const UA_Server *server, + const UA_ByteString *securityPolicyUri); + + /********************/ /* Session Handling */ /********************/ @@ -6485,6 +3923,10 @@ getNamespaceByName(UA_Server *server, const UA_String namespaceUri, size_t *foundIndex); UA_StatusCode +getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex, + UA_String *foundUri); + +UA_StatusCode getBoundSession(UA_Server *server, const UA_SecureChannel *channel, const UA_NodeId *token, UA_Session **session); @@ -6513,12 +3955,6 @@ UA_Server_getSessionById(UA_Server *server, const UA_NodeId *sessionId); /* Node Handling */ /*****************/ -/* Deletes references from the node which are not matching any type in the given - * array. Could be used to e.g. delete all the references, except - * 'HASMODELINGRULE' */ -void UA_Node_deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, - UA_NodeId* referencesSkip); - /* Calls the callback with the node retrieved from the nodestore on top of the * stack. Either a copy or the original node for in-situ editing. Depends on * multithreading and the nodestore.*/ @@ -6533,49 +3969,54 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, /* Utility Functions */ /*********************/ -/* A few global NodeId definitions */ -extern const UA_NodeId subtypeId; -extern const UA_NodeId hierarchicalReferences; - void setupNs1Uri(UA_Server *server); UA_UInt16 addNamespace(UA_Server *server, const UA_String name); UA_Boolean -UA_Node_hasSubTypeOrInstances(const UA_Node *node); +UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head); /* Recursively searches "upwards" in the tree following specific reference types */ UA_Boolean isNodeInTree(UA_Server *server, const UA_NodeId *leafNode, - const UA_NodeId *nodeToFind, const UA_NodeId *referenceTypeIds, - size_t referenceTypeIdsSize); + const UA_NodeId *nodeToFind, const UA_ReferenceTypeSet *relevantRefs); + +/* Convenience function with just a single ReferenceTypeIndex */ +UA_Boolean +isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode, + const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex); /* Returns an array with the hierarchy of nodes. The start nodes can be returned * as well. The returned array starts at the leaf and continues "upwards" or - * "downwards". Duplicate entries are removed. The parameter `walkDownwards` - * indicates the direction of search. */ + * "downwards". Duplicate entries are removed. */ UA_StatusCode -browseRecursive(UA_Server *server, - size_t startNodesSize, const UA_NodeId *startNodes, - size_t refTypesSize, const UA_NodeId *refTypes, - UA_BrowseDirection browseDirection, UA_Boolean includeStartNodes, +browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes, + UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes, + UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes, size_t *resultsSize, UA_ExpandedNodeId **results); -/* If refTypes is non-NULL, tries to realloc and increase the length */ +/* Get the bitfield indices of a ReferenceType and possibly its subtypes. + * refType must point to a ReferenceTypeNode. */ UA_StatusCode -referenceSubtypes(UA_Server *server, const UA_NodeId *refType, - size_t *refTypesSize, UA_NodeId **refTypes); +referenceTypeIndices(UA_Server *server, const UA_NodeId *refType, + UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes); /* Returns the recursive type and interface hierarchy of the node */ UA_StatusCode getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode, UA_NodeId **typeHierarchy, size_t *typeHierarchySize); +/* Returns the recursive interface hierarchy of the node */ +UA_StatusCode +getAllInterfaceChildNodeIds(UA_Server *server, const UA_NodeId *objectNode, const UA_NodeId *objectTypeNode, + UA_NodeId **interfaceChildNodes, size_t *interfaceChildNodesSize); + #ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS -UA_StatusCode UA_EXPORT -UA_getConditionId(UA_Server *server, const UA_NodeId *conditionNodeId, UA_NodeId *outConditionId); +UA_StatusCode +UA_getConditionId(UA_Server *server, const UA_NodeId *conditionNodeId, + UA_NodeId *outConditionId); -void UA_EXPORT +void UA_ConditionList_delete(UA_Server *server); UA_Boolean @@ -6584,15 +4025,12 @@ isConditionOrBranch(UA_Server *server, const UA_NodeId *conditionSource, UA_Boolean *isCallerAC); -#endif//UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS +#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ + /* Returns the type node from the node on the stack top. The type node is pushed * on the stack and returned. */ -const UA_Node * getNodeType(UA_Server *server, const UA_Node *node); - -/* Write a node attribute with a defined session */ -UA_StatusCode -writeWithSession(UA_Server *server, UA_Session *session, - const UA_WriteValue *value); +const UA_Node * +getNodeType(UA_Server *server, const UA_NodeHead *nodeHead); UA_StatusCode sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, @@ -6630,22 +4068,25 @@ addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId *reques void *nodeContext, UA_NodeId *outNewNodeId); UA_StatusCode -setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, - const UA_DataSource dataSource); +addRef(UA_Server *server, UA_Session *session, const UA_NodeId *sourceId, + const UA_NodeId *referenceTypeId, const UA_NodeId *targetId, + UA_Boolean forward); UA_StatusCode -setMethodNode_callback(UA_Server *server, - const UA_NodeId methodNodeId, - UA_MethodCallback methodCallback); +setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, + const UA_DataSource dataSource); UA_StatusCode -writeAttribute(UA_Server *server, const UA_WriteValue *value); +writeAttribute(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, const UA_AttributeId attributeId, + const void *attr, const UA_DataType *attr_type); -UA_StatusCode -writeWithWriteValue(UA_Server *server, const UA_NodeId *nodeId, - const UA_AttributeId attributeId, - const UA_DataType *attr_type, - const void *attr); +static UA_INLINE UA_StatusCode +writeValueAttribute(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, const UA_Variant *value) { + return writeAttribute(server, session, nodeId, UA_ATTRIBUTEID_VALUE, + value, &UA_TYPES[UA_TYPES_VARIANT]); +} UA_DataValue readAttribute(UA_Server *server, const UA_ReadValueId *item, @@ -6664,9 +4105,27 @@ UA_BrowsePathResult translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath); #ifdef UA_ENABLE_SUBSCRIPTIONS -void -monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem); -#endif + +void monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem); + +UA_Subscription * +UA_Server_getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId); + +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS +UA_StatusCode +triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, + const UA_NodeId origin, UA_ByteString *outEventId, + const UA_Boolean deleteEventNode); + +/* Filters the given event with the given filter and writes the results into a + * notification */ +UA_StatusCode +filterEvent(UA_Server *server, UA_Session *session, + const UA_NodeId *eventNode, UA_EventFilter *filter, + UA_EventFieldList *efl, UA_EventFilterResult *result); + +#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ +#endif /* UA_ENABLE_SUBSCRIPTIONS */ UA_BrowsePathResult browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, @@ -6679,6 +4138,9 @@ writeObjectProperty(UA_Server *server, const UA_NodeId objectId, UA_StatusCode getNodeContext(UA_Server *server, UA_NodeId nodeId, void **nodeContext); +UA_StatusCode +setNodeContext(UA_Server *server, UA_NodeId nodeId, void *nodeContext); + void removeCallback(UA_Server *server, UA_UInt64 callbackId); @@ -6696,6 +4158,55 @@ register_server_with_discovery_server(UA_Server *server, const UA_Boolean isUnregister, const char* semaphoreFilePath); #endif + +/***********/ +/* RefTree */ +/***********/ + +/* A RefTree is a sorted set of NodeIds that ensures we consider each node just + * once. It holds a single array for both the ExpandedNodeIds and the entries of + * a tree-structure for fast lookup. A single realloc operation (with some + * pointer repairing) can be used to increase the capacity of the RefTree. + * + * When the RefTree is complete, the tree-part at the end of the targets array + * can be ignored / cut away to use it as a simple ExpandedNodeId array. + * + * The layout of the targets array is as follows: + * + * | Targets [ExpandedNodeId, n times] | Tree [RefEntry, n times] | */ + +#define UA_REFTREE_INITIAL_SIZE 16 + +typedef struct RefEntry { + ZIP_ENTRY(RefEntry) zipfields; + const UA_ExpandedNodeId *target; + UA_UInt32 targetHash; /* Hash of the target nodeid */ +} RefEntry; + +ZIP_HEAD(RefHead, RefEntry); +typedef struct RefHead RefHead; + +typedef struct { + UA_ExpandedNodeId *targets; + RefHead head; + size_t capacity; /* available space */ + size_t size; /* used space */ +} RefTree; + +UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT +RefTree_init(RefTree *rt); + +void RefTree_clear(RefTree *rt); + +UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT +RefTree_addNodeId(RefTree *rt, const UA_NodeId *target, UA_Boolean *duplicate); + +UA_Boolean +RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target); + +UA_Boolean +RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target); + /***************************************/ /* Check Information Model Consistency */ /***************************************/ @@ -6718,12 +4229,31 @@ readValueAttribute(UA_Server *server, UA_Session *session, * - array dimensions. * Sometimes it can be necessary to transform the content of the value, e.g. * byte array to bytestring or uint32 to some enum. If editableValue is non-NULL, - * we try to create a matching variant that points to the original data. */ + * we try to create a matching variant that points to the original data. + * + * The reason is set whenever the return value is false */ UA_Boolean compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId, UA_Int32 targetValueRank, size_t targetArrayDimensionsSize, const UA_UInt32 *targetArrayDimensions, const UA_Variant *value, - const UA_NumericRange *range); + const UA_NumericRange *range, const char **reason); + +/* Is the DataType compatible */ +UA_Boolean +compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType, + const UA_NodeId *constraintDataType); + +/* Set to the target type if compatible */ +void +adjustValueType(UA_Server *server, UA_Variant *value, + const UA_NodeId *targetDataTypeId); + +/* Is the Value compatible with the DataType? Can perform additional checks + * compared to compatibleDataTypes. */ +UA_Boolean +compatibleValueDataType(UA_Server *server, const UA_DataType *dataType, + const UA_NodeId *constraintDataType); + UA_Boolean compatibleArrayDimensions(size_t constraintArrayDimensionsSize, @@ -6740,10 +4270,6 @@ compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session, UA_Int32 valueRank, size_t arrayDimensionsSize); UA_Boolean -compatibleDataType(UA_Server *server, const UA_NodeId *dataType, - const UA_NodeId *constraintDataType, UA_Boolean isValue); - -UA_Boolean compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank); struct BrowseOpts { @@ -6788,6 +4314,39 @@ UA_StatusCode UA_Server_initNS0(UA_Server *server); UA_StatusCode writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, size_t length, const UA_DataType *type); +#ifdef UA_ENABLE_DIAGNOSTICS +void createSessionObject(UA_Server *server, UA_Session *session); + +void createSubscriptionObject(UA_Server *server, UA_Session *session, + UA_Subscription *sub); + +UA_StatusCode +readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value); + +UA_StatusCode +readSubscriptionDiagnosticsArray(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value); + +UA_StatusCode +readSessionDiagnosticsArray(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value); + +UA_StatusCode +readSessionSecurityDiagnostics(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value); +#endif + /***************************/ /* Nodestore Access Macros */ /***************************/ @@ -6801,6 +4360,10 @@ UA_StatusCode writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, #define UA_NODESTORE_GET(server, nodeid) \ server->config.nodestore.getNode(server->config.nodestore.context, nodeid) +/* Returns NULL if the target is an external Reference (per the ExpandedNodeId) */ +const UA_Node * +UA_NODESTORE_GETFROMREF(UA_Server *server, UA_NodePointer target); + #define UA_NODESTORE_RELEASE(server, node) \ server->config.nodestore.releaseNode(server->config.nodestore.context, node) @@ -6818,10 +4381,14 @@ UA_StatusCode writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, #define UA_NODESTORE_REMOVE(server, nodeId) \ server->config.nodestore.removeNode(server->config.nodestore.context, nodeId) +#define UA_NODESTORE_GETREFERENCETYPEID(server, index) \ + server->config.nodestore.getReferenceTypeId(server->config.nodestore.context, \ + index) + _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services.h" ***********************************/ +/**** amalgamated original file "/src/server/ua_services.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -7005,7 +4572,11 @@ void Service_CloseSession(UA_Server *server, UA_SecureChannel *channel, * * AddNodes Service * ^^^^^^^^^^^^^^^^ - * Used to add one or more Nodes into the AddressSpace hierarchy. */ + * Used to add one or more Nodes into the AddressSpace hierarchy. + * If the type or one of the supertypes has any HasInterface references + * (see OPC 10001-7 - Amendment 7, 4.9.2), the child nodes of the interfaces + * are added to the new object. +*/ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request, UA_AddNodesResponse *response); @@ -7013,7 +4584,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, /** * AddReferences Service * ^^^^^^^^^^^^^^^^^^^^^ - * Used to add one or more References to one or more Nodes. */ + * Used to add one or more References to one or more Nodes.*/ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request, UA_AddReferencesResponse *response); @@ -7245,7 +4816,9 @@ void Service_SetMonitoringMode(UA_Server *server, UA_Session *session, * SetTriggering Service * ^^^^^^^^^^^^^^^^^^^^^ * Used to create and delete triggering links for a triggering item. */ -/* Not Implemented */ +void Service_SetTriggering(UA_Server *server, UA_Session *session, + const UA_SetTriggeringRequest *request, + UA_SetTriggeringResponse *response); /** * Subscription Service Set @@ -7287,9 +4860,13 @@ void Service_SetPublishingMode(UA_Server *server, UA_Session *session, * * Note that the service signature is an exception and does not contain a * pointer to a PublishResponse. That is because the service queues up publish - * requests internally and sends responses asynchronously based on timeouts. */ -void Service_Publish(UA_Server *server, UA_Session *session, - const UA_PublishRequest *request, UA_UInt32 requestId); + * requests internally and sends responses asynchronously based on timeouts. + * + * Also, this is the only service method that returns a StatusCode. This + * simplifies keeping track of the diagnostics statistics. */ +UA_StatusCode +Service_Publish(UA_Server *server, UA_Session *session, + const UA_PublishRequest *request, UA_UInt32 requestId); /** * Republish Service @@ -7317,14 +4894,16 @@ void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session, * its Subscriptions to that Session. It may also be used by one Client to take * over a Subscription from another Client by transferring the Subscription to * its Session. */ -/* Not Implemented */ +void Service_TransferSubscriptions(UA_Server *server, UA_Session *session, + const UA_TransferSubscriptionsRequest *request, + UA_TransferSubscriptionsResponse *response); #endif /* UA_ENABLE_SUBSCRIPTIONS */ _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/client/ua_client_internal.h" ***********************************/ +/**** amalgamated original file "/src/client/ua_client_internal.h" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -7419,13 +4998,11 @@ void UA_Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode); typedef struct CustomCallback { - LIST_ENTRY(CustomCallback) pointers; UA_UInt32 callbackId; UA_ClientAsyncServiceCallback userCallback; void *userData; - bool isAsync; void *clientData; } CustomCallback; @@ -7466,7 +5043,6 @@ struct UA_Client { /* Async Service */ LIST_HEAD(, AsyncServiceCall) asyncServiceCalls; - LIST_HEAD(, CustomCallback) customCallbacks; /* Subscriptions */ #ifdef UA_ENABLE_SUBSCRIPTIONS @@ -7480,9 +5056,8 @@ struct UA_Client { void notifyClientState(UA_Client *client); void processERRResponse(UA_Client *client, const UA_ByteString *chunk); void processACKResponse(UA_Client *client, const UA_ByteString *chunk); -void processOPNResponse(UA_Client *client, UA_ByteString *chunk); +void processOPNResponse(UA_Client *client, const UA_ByteString *message); void closeSecureChannel(UA_Client *client); -void renewSecureChannel(UA_Client *client); UA_StatusCode connectIterate(UA_Client *client, UA_UInt32 timeout); @@ -7493,7 +5068,36 @@ receiveResponseAsync(UA_Client *client, UA_UInt32 timeout); _UA_END_DECLS -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/namespace0_generated.h" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_config.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + */ + +#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG + + + +/* Decodes the information from the ByteString. If the decoded content is a + * PubSubConfiguration in a UABinaryFileDataType-object. It will overwrite the + * current PubSub configuration from the server. */ +UA_StatusCode +UA_PubSubManager_loadPubSubConfigFromByteString(UA_Server *server, + const UA_ByteString buffer); + +/* Saves the current PubSub configuration of a server in a byteString. */ +UA_StatusCode +UA_PubSubManager_getEncodedPubSubConfiguration(UA_Server *server, + UA_ByteString *buffer); + + +#endif /* UA_ENABLE_PUBSUB_FILE_CONFIG */ + +/**** amalgamated original file "/build/src_generated/open62541/namespace0_generated.h" ****/ /* WARNING: This is a generated file. * Any manual changes will be overwritten. */ @@ -7544,7 +5148,7 @@ _UA_END_DECLS #endif /* NAMESPACE0_GENERATED_H_ */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_types.c" ***********************************/ +/**** amalgamated original file "/src/ua_types.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -7576,49 +5180,53 @@ _UA_END_DECLS /* Global definition of NULL type instances. These are always zeroed out, as * mandated by the C/C++ standard for global values with no initializer. */ -const UA_String UA_STRING_NULL = {0, NULL}; -const UA_ByteString UA_BYTESTRING_NULL = {0, NULL}; -const UA_Guid UA_GUID_NULL = {0, 0, 0, {0,0,0,0,0,0,0,0}}; -const UA_NodeId UA_NODEID_NULL = {0, UA_NODEIDTYPE_NUMERIC, {0}}; -const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {{0, UA_NODEIDTYPE_NUMERIC, {0}}, {0, NULL}, 0}; - -typedef UA_StatusCode (*UA_copySignature)(const void *src, void *dst, - const UA_DataType *type); -typedef void (*UA_clearSignature)(void *p, const UA_DataType *type); - +const UA_String UA_STRING_NULL = {0}; +const UA_ByteString UA_BYTESTRING_NULL = {0}; +const UA_Guid UA_GUID_NULL = {0}; +const UA_NodeId UA_NODEID_NULL = {0}; +const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {0}; + +typedef UA_StatusCode +(*UA_copySignature)(const void *src, void *dst, const UA_DataType *type); extern const UA_copySignature copyJumpTable[UA_DATATYPEKINDS]; + +typedef void (*UA_clearSignature)(void *p, const UA_DataType *type); extern const UA_clearSignature clearJumpTable[UA_DATATYPEKINDS]; -/* TODO: The standard-defined types are ordered. See if binary search is - * more efficient. */ -const UA_DataType * -UA_findDataType(const UA_NodeId *typeId) { - if(typeId->identifierType != UA_NODEIDTYPE_NUMERIC) - return NULL; +typedef UA_Order +(*UA_orderSignature)(const void *p1, const void *p2, const UA_DataType *type); +extern const UA_orderSignature orderJumpTable[UA_DATATYPEKINDS]; - /* Always look in built-in types first - * (may contain data types from all namespaces) */ +const UA_DataType * +UA_findDataTypeWithCustom(const UA_NodeId *typeId, + const UA_DataTypeArray *customTypes) { + /* Always look in built-in types first (may contain data types from all + * namespaces). + * + * TODO: The standard-defined types are ordered. See if binary search is + * more efficient. */ for(size_t i = 0; i < UA_TYPES_COUNT; ++i) { - if(UA_TYPES[i].typeId.identifier.numeric == typeId->identifier.numeric - && UA_TYPES[i].typeId.namespaceIndex == typeId->namespaceIndex) + if(UA_NodeId_equal(&UA_TYPES[i].typeId, typeId)) return &UA_TYPES[i]; } - /* TODO When other namespace look in custom types, too, requires access to custom types array here! */ - /*if(typeId->namespaceIndex != 0) { - size_t customTypesArraySize; - const UA_DataType *customTypesArray; - UA_getCustomTypes(&customTypesArraySize, &customTypesArray); - for(size_t i = 0; i < customTypesArraySize; ++i) { - if(customTypesArray[i].typeId.identifier.numeric == typeId->identifier.numeric - && customTypesArray[i].typeId.namespaceIndex == typeId->namespaceIndex) - return &customTypesArray[i]; + /* Search in the customTypes */ + while(customTypes) { + for(size_t i = 0; i < customTypes->typesSize; ++i) { + if(UA_NodeId_equal(&customTypes->types[i].typeId, typeId)) + return &customTypes->types[i]; } - }*/ + customTypes = customTypes->next; + } return NULL; } +const UA_DataType * +UA_findDataType(const UA_NodeId *typeId) { + return UA_findDataTypeWithCustom(typeId, NULL); +} + /***************************/ /* Random Number Generator */ /***************************/ @@ -7648,7 +5256,7 @@ UA_String_fromChars(const char *src) { s.length = strlen(src); if(s.length > 0) { s.data = (u8*)UA_malloc(s.length); - if(!s.data) { + if(UA_UNLIKELY(!s.data)) { s.length = 0; return s; } @@ -7659,26 +5267,42 @@ UA_String_fromChars(const char *src) { return s; } +static UA_Order +stringOrder(const UA_String *p1, const UA_String *p2, const UA_DataType *type); +static UA_Order +guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *type); +static UA_Order +qualifiedNameOrder(const UA_QualifiedName *p1, const UA_QualifiedName *p2, + const UA_DataType *type); + UA_Boolean UA_String_equal(const UA_String *s1, const UA_String *s2) { + return (stringOrder(s1, s2, NULL) == UA_ORDER_EQ); +} + +/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles + * ASCII strings, and not UTF8! */ +UA_Boolean +UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2) { if(s1->length != s2->length) return false; if(s1->length == 0) return true; if(s2->data == NULL) return false; - i32 is = memcmp((char const*)s1->data, - (char const*)s2->data, s1->length); - return (is == 0) ? true : false; + + //FIXME this currently does not handle UTF8 + return UA_strncasecmp((const char*)s1->data, (const char*)s2->data, s1->length) == 0; } static UA_StatusCode String_copy(UA_String const *src, UA_String *dst, const UA_DataType *_) { - UA_StatusCode retval = UA_Array_copy(src->data, src->length, (void**)&dst->data, - &UA_TYPES[UA_TYPES_BYTE]); - if(retval == UA_STATUSCODE_GOOD) + UA_StatusCode res = + UA_Array_copy(src->data, src->length, (void**)&dst->data, + &UA_TYPES[UA_TYPES_BYTE]); + if(res == UA_STATUSCODE_GOOD) dst->length = src->length; - return retval; + return res; } static void @@ -7688,7 +5312,8 @@ String_clear(UA_String *s, const UA_DataType *_) { /* QualifiedName */ static UA_StatusCode -QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst, const UA_DataType *_) { +QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst, + const UA_DataType *_) { dst->namespaceIndex = src->namespaceIndex; return String_copy(&src->name, &dst->name, NULL); } @@ -7707,43 +5332,39 @@ UA_QualifiedName_hash(const UA_QualifiedName *q) { UA_Boolean UA_QualifiedName_equal(const UA_QualifiedName *qn1, const UA_QualifiedName *qn2) { - if(qn1 == NULL || qn2 == NULL) - return false; - if(qn1->namespaceIndex != qn2->namespaceIndex) - return false; - if(qn1->name.length != qn2->name.length) - return false; - return (memcmp((char const*)qn1->name.data, - (char const*)qn2->name.data, qn1->name.length) == 0); + return (qualifiedNameOrder(qn1, qn2, NULL) == UA_ORDER_EQ); } /* DateTime */ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t) { - /* Calculating the the milli-, micro- and nanoseconds */ - UA_DateTimeStruct dateTimeStruct; - if(t >= 0) { - dateTimeStruct.nanoSec = (u16)((t % 10) * 100); - dateTimeStruct.microSec = (u16)((t % 10000) / 10); - dateTimeStruct.milliSec = (u16)((t % 10000000) / 10000); - } else { - dateTimeStruct.nanoSec = (u16)(((t % 10 + t) % 10) * 100); - dateTimeStruct.microSec = (u16)(((t % 10000 + t) % 10000) / 10); - dateTimeStruct.milliSec = (u16)(((t % 10000000 + t) % 10000000) / 10000); - } - - /* Calculating the unix time with #include <time.h> */ + /* Divide, then subtract -> avoid underflow. Also, negative numbers are + * rounded up, not down. */ long long secSinceUnixEpoch = (long long)(t / UA_DATETIME_SEC) - (long long)(UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC); + + /* Negative fractions of a second? Remove one full second from the epoch + * distance and allow only a positive fraction. */ + UA_DateTime frac = t % UA_DATETIME_SEC; + if(frac < 0) { + secSinceUnixEpoch--; + frac += UA_DATETIME_SEC; + } + struct mytm ts; memset(&ts, 0, sizeof(struct mytm)); __secs_to_tm(secSinceUnixEpoch, &ts); - dateTimeStruct.sec = (u16)ts.tm_sec; - dateTimeStruct.min = (u16)ts.tm_min; - dateTimeStruct.hour = (u16)ts.tm_hour; - dateTimeStruct.day = (u16)ts.tm_mday; + + UA_DateTimeStruct dateTimeStruct; + dateTimeStruct.year = (i16)(ts.tm_year + 1900); dateTimeStruct.month = (u16)(ts.tm_mon + 1); - dateTimeStruct.year = (u16)(ts.tm_year + 1900); + dateTimeStruct.day = (u16)ts.tm_mday; + dateTimeStruct.hour = (u16)ts.tm_hour; + dateTimeStruct.min = (u16)ts.tm_min; + dateTimeStruct.sec = (u16)ts.tm_sec; + dateTimeStruct.milliSec = (u16)((frac % 10000000) / 10000); + dateTimeStruct.microSec = (u16)((frac % 10000) / 10); + dateTimeStruct.nanoSec = (u16)((frac % 10) * 100); return dateTimeStruct; } @@ -7771,9 +5392,7 @@ UA_DateTime_fromStruct(UA_DateTimeStruct ts) { /* Guid */ UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) { - if(memcmp(g1, g2, sizeof(UA_Guid)) == 0) - return true; - return false; + return (guidOrder(g1, g2, NULL) == UA_ORDER_EQ); } UA_Guid @@ -7803,7 +5422,7 @@ UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) { if(length == 0) return UA_STATUSCODE_GOOD; bs->data = (u8*)UA_malloc(length); - if(!bs->data) + if(UA_UNLIKELY(!bs->data)) return UA_STATUSCODE_BADOUTOFMEMORY; bs->length = length; return UA_STATUSCODE_GOOD; @@ -7855,11 +5474,10 @@ UA_NodeId_isNull(const UA_NodeId *p) { case UA_NODEIDTYPE_NUMERIC: return (p->identifier.numeric == 0); case UA_NODEIDTYPE_STRING: - return UA_String_equal(&p->identifier.string, &UA_STRING_NULL); + case UA_NODEIDTYPE_BYTESTRING: + return (p->identifier.string.length == 0); /* Null and empty string */ case UA_NODEIDTYPE_GUID: return UA_Guid_equal(&p->identifier.guid, &UA_GUID_NULL); - case UA_NODEIDTYPE_BYTESTRING: - return UA_ByteString_equal(&p->identifier.byteString, &UA_BYTESTRING_NULL); } return false; } @@ -7868,81 +5486,39 @@ UA_NodeId_isNull(const UA_NodeId *p) { UA_Order UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2) { /* Compare namespaceIndex */ - if(n1->namespaceIndex < n2->namespaceIndex) - return UA_ORDER_LESS; - if(n1->namespaceIndex > n2->namespaceIndex) - return UA_ORDER_MORE; + if(n1->namespaceIndex != n2->namespaceIndex) + return (n1->namespaceIndex < n2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE; /* Compare identifierType */ - if(n1->identifierType < n2->identifierType) - return UA_ORDER_LESS; - if(n1->identifierType > n2->identifierType) - return UA_ORDER_MORE; + if(n1->identifierType != n2->identifierType) + return (n1->identifierType < n2->identifierType) ? UA_ORDER_LESS : UA_ORDER_MORE; /* Compare the identifier */ switch(n1->identifierType) { case UA_NODEIDTYPE_NUMERIC: - if(n1->identifier.numeric < n2->identifier.numeric) - return UA_ORDER_LESS; - if(n1->identifier.numeric > n2->identifier.numeric) - return UA_ORDER_MORE; - break; - case UA_NODEIDTYPE_GUID: - if(n1->identifier.guid.data1 < n2->identifier.guid.data1) { - return UA_ORDER_LESS; - } else if(n1->identifier.guid.data1 > n2->identifier.guid.data1) { - return UA_ORDER_MORE; - } else if(n1->identifier.guid.data2 < n2->identifier.guid.data2) { - return UA_ORDER_LESS; - } else if(n1->identifier.guid.data2 > n2->identifier.guid.data2) { - return UA_ORDER_MORE; - } else if(n1->identifier.guid.data3 < n2->identifier.guid.data3) { - return UA_ORDER_LESS; - } else if(n1->identifier.guid.data3 > n2->identifier.guid.data3) { - return UA_ORDER_MORE; - } else { - int cmp = memcmp(n1->identifier.guid.data4, n2->identifier.guid.data4, 8); - - if(cmp < 0) return UA_ORDER_LESS; - if(cmp > 0) return UA_ORDER_MORE; + default: + if(n1->identifier.numeric != n2->identifier.numeric) + return (n1->identifier.numeric < n2->identifier.numeric) ? + UA_ORDER_LESS : UA_ORDER_MORE; + return UA_ORDER_EQ; - } + case UA_NODEIDTYPE_GUID: + return guidOrder(&n1->identifier.guid, &n2->identifier.guid, NULL); - break; case UA_NODEIDTYPE_STRING: - case UA_NODEIDTYPE_BYTESTRING: { - size_t minLength = UA_MIN(n1->identifier.string.length, n2->identifier.string.length); - int cmp = strncmp((const char*)n1->identifier.string.data, - (const char*)n2->identifier.string.data, - minLength); - if(cmp < 0) - return UA_ORDER_LESS; - if(cmp > 0) - return UA_ORDER_MORE; - - if(n1->identifier.string.length < n2->identifier.string.length) - return UA_ORDER_LESS; - if(n1->identifier.string.length > n2->identifier.string.length) - return UA_ORDER_MORE; - break; - } - default: - break; + case UA_NODEIDTYPE_BYTESTRING: + return stringOrder(&n1->identifier.string, &n2->identifier.string, NULL); } - - return UA_ORDER_EQ; } -/* FNV non-cryptographic hash function. See - * https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */ -#define FNV_PRIME_32 16777619 +/* sdbm-hash (http://www.cse.yorku.ca/~oz/hash.html) */ u32 -UA_ByteString_hash(u32 fnv, const u8 *buf, size_t size) { - for(size_t i = 0; i < size; ++i) { - fnv = fnv ^ (buf[i]); - fnv = fnv * FNV_PRIME_32; - } - return fnv; +UA_ByteString_hash(u32 initialHashValue, + const u8 *data, size_t size) { + u32 h = initialHashValue; + for(size_t i = 0; i < size; i++) + h = data[i] + (h << 6) + (h << 16) - h; + return h; } u32 @@ -7950,13 +5526,15 @@ UA_NodeId_hash(const UA_NodeId *n) { switch(n->identifierType) { case UA_NODEIDTYPE_NUMERIC: default: - // shift knuth multiplication to use highest 32 bits and after addition make sure we don't have an integer overflow - return (u32)((n->namespaceIndex + ((n->identifier.numeric * (u64)2654435761) >> (32))) & UINT32_C(4294967295)); /* Knuth's multiplicative hashing */ + return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.numeric, + sizeof(UA_UInt32)); case UA_NODEIDTYPE_STRING: case UA_NODEIDTYPE_BYTESTRING: - return UA_ByteString_hash(n->namespaceIndex, n->identifier.string.data, n->identifier.string.length); + return UA_ByteString_hash(n->namespaceIndex, n->identifier.string.data, + n->identifier.string.length); case UA_NODEIDTYPE_GUID: - return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.guid, sizeof(UA_Guid)); + return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.guid, + sizeof(UA_Guid)); } } @@ -7976,34 +5554,30 @@ ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNodeId *dst, return retval; } +UA_Boolean +UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n) { + return (n->namespaceUri.length == 0 && n->serverIndex == 0); +} + UA_Order UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1, const UA_ExpandedNodeId *n2) { - if(n1->serverIndex > n2->serverIndex) - return UA_ORDER_MORE; - if(n1->serverIndex < n2->serverIndex) - return UA_ORDER_LESS; - if(n1->namespaceUri.length > 0) { - if(n1->namespaceUri.length > n2->namespaceUri.length) - return UA_ORDER_MORE; - if(n1->namespaceUri.length < n2->namespaceUri.length) - return UA_ORDER_LESS; - int cmp = strncmp((const char*)n1->namespaceUri.data, - (const char*)n2->namespaceUri.data, - n1->namespaceUri.length); - if(cmp < 0) - return UA_ORDER_LESS; - if(cmp > 0) - return UA_ORDER_MORE; - } + if(n1->serverIndex != n2->serverIndex) + return (n1->serverIndex < n2->serverIndex) ? UA_ORDER_LESS : UA_ORDER_MORE; + UA_Order o = stringOrder(&n1->namespaceUri, &n2->namespaceUri, NULL); + if(o != UA_ORDER_EQ) + return o; return UA_NodeId_order(&n1->nodeId, &n2->nodeId); } u32 UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n) { u32 h = UA_NodeId_hash(&n->nodeId); - h = UA_ByteString_hash(h, (const UA_Byte*)&n->serverIndex, 4); - return UA_ByteString_hash(h, n->namespaceUri.data, n->namespaceUri.length); + if(n->serverIndex != 0) + h = UA_ByteString_hash(h, (const UA_Byte*)&n->serverIndex, 4); + if(n->namespaceUri.length != 0) + h = UA_ByteString_hash(h, n->namespaceUri.data, n->namespaceUri.length); + return h; } /* ExtensionObject */ @@ -8054,17 +5628,65 @@ ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst, return retval; } +void +UA_ExtensionObject_setValue(UA_ExtensionObject *eo, + void * UA_RESTRICT p, + const UA_DataType *type) { + UA_ExtensionObject_init(eo); + eo->content.decoded.data = p; + eo->content.decoded.type = type; + eo->encoding = UA_EXTENSIONOBJECT_DECODED; +} + +void +UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo, + void * UA_RESTRICT p, + const UA_DataType *type) { + UA_ExtensionObject_init(eo); + eo->content.decoded.data = p; + eo->content.decoded.type = type; + eo->encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; +} + +UA_StatusCode +UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo, + void * UA_RESTRICT p, + const UA_DataType *type) { + UA_ExtensionObject_init(eo); + + /* Make a copy of the value */ + void *val = UA_malloc(type->memSize); + if(UA_UNLIKELY(!val)) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_StatusCode res = UA_copy(p, val, type); + if(UA_UNLIKELY(res != UA_STATUSCODE_GOOD)) { + UA_free(val); + return res; + } + + /* Set the ExtensionObject */ + eo->content.decoded.data = val; + eo->content.decoded.type = type; + eo->encoding = UA_EXTENSIONOBJECT_DECODED; + return UA_STATUSCODE_GOOD; +} + /* Variant */ static void Variant_clear(UA_Variant *p, const UA_DataType *_) { - if(p->storageType != UA_VARIANT_DATA) + /* The content is "borrowed" */ + if(p->storageType == UA_VARIANT_DATA_NODELETE) return; + + /* Delete the value */ if(p->type && p->data > UA_EMPTY_ARRAY_SENTINEL) { if(p->arrayLength == 0) p->arrayLength = 1; UA_Array_delete(p->data, p->arrayLength, p->type); p->data = NULL; } + + /* Delete the array dimensions */ if((void*)p->arrayDimensions > UA_EMPTY_ARRAY_SENTINEL) UA_free(p->arrayDimensions); } @@ -8100,13 +5722,13 @@ UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, } UA_StatusCode -UA_Variant_setScalarCopy(UA_Variant *v, const void *p, +UA_Variant_setScalarCopy(UA_Variant *v, const void * UA_RESTRICT p, const UA_DataType *type) { void *n = UA_malloc(type->memSize); - if(!n) + if(UA_UNLIKELY(!n)) return UA_STATUSCODE_BADOUTOFMEMORY; UA_StatusCode retval = UA_copy(p, n, type); - if(retval != UA_STATUSCODE_GOOD) { + if(UA_UNLIKELY(retval != UA_STATUSCODE_GOOD)) { UA_free(n); //cppcheck-suppress memleak return retval; @@ -8125,7 +5747,7 @@ void UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, } UA_StatusCode -UA_Variant_setArrayCopy(UA_Variant *v, const void *array, +UA_Variant_setArrayCopy(UA_Variant *v, const void * UA_RESTRICT array, size_t arraySize, const UA_DataType *type) { UA_Variant_init(v); UA_StatusCode retval = UA_Array_copy(array, arraySize, &v->data, type); @@ -8136,42 +5758,36 @@ UA_Variant_setArrayCopy(UA_Variant *v, const void *array, return UA_STATUSCODE_GOOD; } -/* Test if a range is compatible with a variant. If yes, the following values - * are set: - * - total: how many elements are in the range - * - block: how big is each contiguous block of elements in the variant that - * maps into the range - * - stride: how many elements are between the blocks (beginning to beginning) - * - first: where does the first block begin */ +/* Test if a range is compatible with a variant. This may adjust the upper bound + * (max) in order to fit the variant. */ static UA_StatusCode -computeStrides(const UA_Variant *v, const UA_NumericRange range, - size_t *total, size_t *block, size_t *stride, size_t *first) { +checkAdjustRange(const UA_Variant *v, UA_NumericRange *range) { /* Test for max array size (64bit only) */ #if (SIZE_MAX > 0xffffffff) if(v->arrayLength > UA_UINT32_MAX) return UA_STATUSCODE_BADINTERNALERROR; #endif - - /* Test the integrity of the source variant dimensions, make dimensions - * vector of one dimension if none defined */ u32 arrayLength = (u32)v->arrayLength; - const u32 *dims = &arrayLength; - size_t dims_count = 1; - if(v->arrayDimensionsSize > 0) { - size_t elements = 1; - dims_count = v->arrayDimensionsSize; - dims = (u32*)v->arrayDimensions; - for(size_t i = 0; i < dims_count; ++i) - elements *= dims[i]; - if(elements != v->arrayLength) - return UA_STATUSCODE_BADINTERNALERROR; + + /* Assume one array dimension if none defined */ + const u32 *dims = v->arrayDimensions; + size_t dims_count = v->arrayDimensionsSize; + if(v->arrayDimensionsSize == 0) { + dims_count = 1; + dims = &arrayLength; } - UA_assert(dims_count > 0); - /* Upper bound of the dimensions for stack-allocation */ - if(dims_count > UA_MAX_ARRAY_DIMS) + /* Does the range match the dimension of the variant? */ + if(range->dimensionsSize != dims_count) + return UA_STATUSCODE_BADINDEXRANGENODATA; + + /* Check that the number of elements in the variant matches the array + * dimensions */ + size_t elements = 1; + for(size_t i = 0; i < dims_count; ++i) + elements *= dims[i]; + if(elements != v->arrayLength) return UA_STATUSCODE_BADINTERNALERROR; - UA_UInt32 realmax[UA_MAX_ARRAY_DIMS]; /* Test the integrity of the range and compute the max index used for every * dimension. The standard says in Part 4, Section 7.22: @@ -8179,25 +5795,44 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range, * When reading a value, the indexes may not specify a range that is within * the bounds of the array. The Server shall return a partial result if some * elements exist within the range. */ - size_t count = 1; - if(range.dimensionsSize != dims_count) - return UA_STATUSCODE_BADINDEXRANGENODATA; for(size_t i = 0; i < dims_count; ++i) { - if(range.dimensions[i].min > range.dimensions[i].max) + if(range->dimensions[i].min > range->dimensions[i].max) return UA_STATUSCODE_BADINDEXRANGEINVALID; - if(range.dimensions[i].min >= dims[i]) + if(range->dimensions[i].min >= dims[i]) return UA_STATUSCODE_BADINDEXRANGENODATA; - if(range.dimensions[i].max < dims[i]) - realmax[i] = range.dimensions[i].max; - else - realmax[i] = dims[i] - 1; - - count *= (realmax[i] - range.dimensions[i].min) + 1; + /* Reduce the max to fit the variant */ + if(range->dimensions[i].max >= dims[i]) + range->dimensions[i].max = dims[i] - 1; } + return UA_STATUSCODE_GOOD; +} + +/* Computes the stride for copying the range elements. + * - total: how many elements are in the range + * - block: how big is each contiguous block of elements in the variant that + * maps into the range + * - stride: how many elements are between the blocks (beginning to beginning) + * - first: where does the first block begin */ +static void +computeStrides(const UA_Variant *v, const UA_NumericRange range, + size_t *total, size_t *block, size_t *stride, size_t *first) { + /* Number of total elements to be copied */ + size_t count = 1; + for(size_t i = 0; i < range.dimensionsSize; ++i) + count *= (range.dimensions[i].max - range.dimensions[i].min) + 1; *total = count; + /* Assume one array dimension if none defined */ + u32 arrayLength = (u32)v->arrayLength; + const u32 *dims = v->arrayDimensions; + size_t dims_count = v->arrayDimensionsSize; + if(v->arrayDimensionsSize == 0) { + dims_count = 1; + dims = &arrayLength; + } + /* Compute the stride length and the position of the first element */ *block = count; /* Assume the range describes the entire array. */ *stride = v->arrayLength; /* So it can be copied as a contiguous block. */ @@ -8206,7 +5841,7 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range, UA_Boolean found_contiguous = false; for(size_t k = dims_count; k > 0;) { --k; - size_t dimrange = 1 + realmax[k] - range.dimensions[k].min; + size_t dimrange = 1 + range.dimensions[k].max - range.dimensions[k].min; if(!found_contiguous && dimrange != dims[k]) { /* Found the maximum block that can be copied contiguously */ found_contiguous = true; @@ -8216,7 +5851,6 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range, *first += running_dimssize * range.dimensions[k].min; running_dimssize *= dims[k]; } - return UA_STATUSCODE_GOOD; } /* Is the type string-like? */ @@ -8253,19 +5887,30 @@ copySubString(const UA_String *src, UA_String *dst, } UA_StatusCode -UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, +UA_Variant_copyRange(const UA_Variant *src, UA_Variant * UA_RESTRICT dst, const UA_NumericRange range) { if(!src->type) return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_Boolean isScalar = UA_Variant_isScalar(src); UA_Boolean stringLike = isStringLike(src->type); - UA_Variant arraySrc; + + /* Upper bound of the dimensions for stack-allocation */ + if(range.dimensionsSize > UA_MAX_ARRAY_DIMS) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Copy the const range to a mutable stack location */ + UA_NumericRangeDimension thisrangedims[UA_MAX_ARRAY_DIMS]; + memcpy(thisrangedims, range.dimensions, sizeof(UA_NumericRangeDimension) * range.dimensionsSize); + UA_NumericRange thisrange = {range.dimensionsSize, thisrangedims}; + + UA_NumericRangeDimension scalarThisDimension = {0,0}; /* a single entry */ + UA_NumericRange nextrange = {0, NULL}; /* Extract the range for copying at this level. The remaining range is dealt * with in the "scalar" type that may define an array by itself (string, * variant, ...). */ - UA_NumericRange thisrange, nextrange; - UA_NumericRangeDimension scalarThisDimension = {0,0}; /* a single entry */ + UA_Variant arraySrc; if(isScalar) { /* Replace scalar src with array of length 1 */ arraySrc = *src; @@ -8282,19 +5927,19 @@ UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, dims = 1; if(dims > range.dimensionsSize) return UA_STATUSCODE_BADINDEXRANGEINVALID; - thisrange = range; thisrange.dimensionsSize = dims; nextrange.dimensions = &range.dimensions[dims]; nextrange.dimensionsSize = range.dimensionsSize - dims; } - /* Compute the strides */ - size_t count, block, stride, first; - UA_StatusCode retval = computeStrides(src, thisrange, &count, - &block, &stride, &first); + UA_StatusCode retval = checkAdjustRange(src, &thisrange); if(retval != UA_STATUSCODE_GOOD) return retval; + /* Compute the strides */ + size_t count, block, stride, first; + computeStrides(src, thisrange, &count, &block, &stride, &first); + /* Allocate the array */ UA_Variant_init(dst); dst->data = UA_Array_new(count, src->type); @@ -8387,12 +6032,25 @@ UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, static UA_StatusCode Variant_setRange(UA_Variant *v, void *array, size_t arraySize, const UA_NumericRange range, UA_Boolean copy) { - /* Compute the strides */ - size_t count, block, stride, first; - UA_StatusCode retval = computeStrides(v, range, &count, - &block, &stride, &first); + if(!v->type) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + /* Upper bound of the dimensions for stack-allocation */ + if(range.dimensionsSize > UA_MAX_ARRAY_DIMS) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Copy the const range to a mutable stack location */ + UA_NumericRangeDimension thisrangedims[UA_MAX_ARRAY_DIMS]; + memcpy(thisrangedims, range.dimensions, sizeof(UA_NumericRangeDimension) * range.dimensionsSize); + UA_NumericRange thisrange = {range.dimensionsSize, thisrangedims}; + + UA_StatusCode retval = checkAdjustRange(v, &thisrange); if(retval != UA_STATUSCODE_GOOD) return retval; + + /* Compute the strides */ + size_t count, block, stride, first; + computeStrides(v, range, &count, &block, &stride, &first); if(count != arraySize) return UA_STATUSCODE_BADINDEXRANGEINVALID; @@ -8433,7 +6091,7 @@ UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, } UA_StatusCode -UA_Variant_setRangeCopy(UA_Variant *v, const void *array, +UA_Variant_setRangeCopy(UA_Variant *v, const void * UA_RESTRICT array, size_t arraySize, const UA_NumericRange range) { return Variant_setRange(v, (void*)(uintptr_t)array, arraySize, range, true); @@ -8471,6 +6129,17 @@ DataValue_copy(UA_DataValue const *src, UA_DataValue *dst, return retval; } +UA_StatusCode +UA_DataValue_copyVariantRange(const UA_DataValue *src, UA_DataValue * UA_RESTRICT dst, + const UA_NumericRange range) { + memcpy(dst, src, sizeof(UA_DataValue)); + UA_Variant_init(&dst->value); + UA_StatusCode retval = UA_Variant_copyRange(&src->value, &dst->value, range); + if(retval != UA_STATUSCODE_GOOD) + DataValue_clear(dst, NULL); + return retval; +} + /* DiagnosticInfo */ static void DiagnosticInfo_clear(UA_DiagnosticInfo *p, const UA_DataType *_) { @@ -8491,8 +6160,9 @@ DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst, if(src->hasAdditionalInfo) retval = UA_String_copy(&src->additionalInfo, &dst->additionalInfo); if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) { - dst->innerDiagnosticInfo = (UA_DiagnosticInfo*)UA_malloc(sizeof(UA_DiagnosticInfo)); - if(dst->innerDiagnosticInfo) { + dst->innerDiagnosticInfo = (UA_DiagnosticInfo*) + UA_malloc(sizeof(UA_DiagnosticInfo)); + if(UA_LIKELY(dst->innerDiagnosticInfo != NULL)) { retval |= DiagnosticInfo_copy(src->innerDiagnosticInfo, dst->innerDiagnosticInfo, NULL); dst->hasInnerDiagnosticInfo = true; @@ -8549,10 +6219,9 @@ copyStructure(const void *src, void *dst, const UA_DataType *type) { UA_StatusCode retval = UA_STATUSCODE_GOOD; uintptr_t ptrs = (uintptr_t)src; uintptr_t ptrd = (uintptr_t)dst; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; for(size_t i = 0; i < type->membersSize; ++i) { const UA_DataTypeMember *m = &type->members[i]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptrs += m->padding; ptrd += m->padding; if(!m->isOptional) { @@ -8608,14 +6277,28 @@ copyUnion(const void *src, void *dst, const UA_DataType *type) { UA_copy((const UA_UInt32 *) ptrs, (UA_UInt32 *) ptrd, &UA_TYPES[UA_TYPES_UINT32]); if(selection == 0) return UA_STATUSCODE_GOOD; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; const UA_DataTypeMember *m = &type->members[selection-1]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; - ptrs += UA_TYPES[UA_TYPES_UINT32].memSize; - ptrd += UA_TYPES[UA_TYPES_UINT32].memSize; + const UA_DataType *mt = m->memberType; ptrs += m->padding; ptrd += m->padding; - return UA_copy((const void *) ptrs, (void *) ptrd, mt); + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + if (m->isArray) { + size_t *dst_size = (size_t*)ptrd; + const size_t size = *((const size_t*)ptrs); + ptrs += sizeof(size_t); + ptrd += sizeof(size_t); + retval = UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt); + if(retval == UA_STATUSCODE_GOOD) + *dst_size = size; + else + *dst_size = 0; + } else { + retval = copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt); + } + + return retval; } static UA_StatusCode @@ -8669,10 +6352,9 @@ UA_copy(const void *src, void *dst, const UA_DataType *type) { static void clearStructure(void *p, const UA_DataType *type) { uintptr_t ptr = (uintptr_t)p; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; for(size_t i = 0; i < type->membersSize; ++i) { const UA_DataTypeMember *m = &type->members[i]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptr += m->padding; if(!m->isOptional) { if(!m->isArray) { @@ -8712,12 +6394,16 @@ clearUnion(void *p, const UA_DataType *type) { UA_UInt32 selection = *(UA_UInt32 *)ptr; if(selection == 0) return; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; const UA_DataTypeMember *m = &type->members[selection-1]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; - ptr += UA_TYPES[UA_TYPES_UINT32].memSize; + const UA_DataType *mt = m->memberType; ptr += m->padding; - UA_clear((void *) ptr, mt); + if (m->isArray) { + size_t length = *(size_t *)ptr; + ptr += sizeof(size_t); + UA_Array_delete(*(void **)ptr, length, mt); + } else { + UA_clear((void *) ptr, mt); + } } static void nopClear(void *p, const UA_DataType *type) { } @@ -8770,6 +6456,427 @@ UA_delete(void *p, const UA_DataType *type) { } /******************/ +/* Value Ordering */ +/******************/ + +#define UA_NUMERICORDER(NAME, TYPE) \ + static UA_Order \ + NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \ + if(*p1 != *p2) \ + return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE; \ + return UA_ORDER_EQ; \ + } + +UA_NUMERICORDER(booleanOrder, UA_Boolean) +UA_NUMERICORDER(sByteOrder, UA_SByte) +UA_NUMERICORDER(byteOrder, UA_Byte) +UA_NUMERICORDER(int16Order, UA_Int16) +UA_NUMERICORDER(uInt16Order, UA_UInt16) +UA_NUMERICORDER(int32Order, UA_Int32) +UA_NUMERICORDER(uInt32Order, UA_UInt32) +UA_NUMERICORDER(int64Order, UA_Int64) +UA_NUMERICORDER(uInt64Order, UA_UInt64) + +#define UA_FLOATORDER(NAME, TYPE) \ + static UA_Order \ + NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \ + if(*p1 != *p2) { \ + /* p1 is NaN */ \ + if(*p1 != *p1) { \ + if(*p2 != *p2) \ + return UA_ORDER_EQ; \ + return UA_ORDER_LESS; \ + } \ + /* p2 is NaN */ \ + if(*p2 != *p2) \ + return UA_ORDER_MORE; \ + return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE; \ + } \ + return UA_ORDER_EQ; \ + } + +UA_FLOATORDER(floatOrder, UA_Float) +UA_FLOATORDER(doubleOrder, UA_Double) + +static UA_Order +guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *type) { + if(p1->data1 != p2->data1) + return (p1->data1 < p2->data1) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->data2 != p2->data2) + return (p1->data2 < p2->data2) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->data3 != p2->data3) + return (p1->data3 < p2->data3) ? UA_ORDER_LESS : UA_ORDER_MORE; + int cmp = memcmp(p1->data4, p2->data4, 8); + if(cmp != 0) + return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE; + return UA_ORDER_EQ; +} + +static UA_Order +stringOrder(const UA_String *p1, const UA_String *p2, const UA_DataType *type) { + if(p1->length != p2->length) + return (p1->length < p2->length) ? UA_ORDER_LESS : UA_ORDER_MORE; + /* For zero-length arrays, every pointer not NULL is considered a + * UA_EMPTY_ARRAY_SENTINEL. */ + if(p1->data == p2->data) return UA_ORDER_EQ; + if(p1->data == NULL) return UA_ORDER_LESS; + if(p2->data == NULL) return UA_ORDER_MORE; + int cmp = memcmp((const char*)p1->data, (const char*)p2->data, p1->length); + if(cmp != 0) + return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE; + return UA_ORDER_EQ; +} + +static UA_Order +nodeIdOrder(const UA_NodeId *p1, const UA_NodeId *p2, const UA_DataType *type) { + return UA_NodeId_order(p1, p2); +} + +static UA_Order +expandedNodeIdOrder(const UA_ExpandedNodeId *p1, const UA_ExpandedNodeId *p2, + const UA_DataType *type) { + return UA_ExpandedNodeId_order(p1, p2); +} + +static UA_Order +qualifiedNameOrder(const UA_QualifiedName *p1, const UA_QualifiedName *p2, + const UA_DataType *type) { + if(p1->namespaceIndex != p2->namespaceIndex) + return (p1->namespaceIndex < p2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE; + return stringOrder(&p1->name, &p2->name, NULL); +} + +static UA_Order +localizedTextOrder(const UA_LocalizedText *p1, const UA_LocalizedText *p2, + const UA_DataType *type) { + UA_Order o = stringOrder(&p1->locale, &p2->locale, NULL); + if(o != UA_ORDER_EQ) + return o; + return stringOrder(&p1->text, &p2->text, NULL); +} + +static UA_Order +extensionObjectOrder(const UA_ExtensionObject *p1, const UA_ExtensionObject *p2, + const UA_DataType *type) { + UA_ExtensionObjectEncoding enc1 = p1->encoding; + UA_ExtensionObjectEncoding enc2 = p2->encoding; + if(enc1 > UA_EXTENSIONOBJECT_DECODED) + enc1 = UA_EXTENSIONOBJECT_DECODED; + if(enc2 > UA_EXTENSIONOBJECT_DECODED) + enc2 = UA_EXTENSIONOBJECT_DECODED; + if(enc1 != enc2) + return (enc1 < enc2) ? UA_ORDER_LESS : UA_ORDER_MORE; + + switch(enc1) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + return UA_ORDER_EQ; + + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + case UA_EXTENSIONOBJECT_ENCODED_XML: { + UA_Order o = UA_NodeId_order(&p1->content.encoded.typeId, + &p2->content.encoded.typeId); + if(o == UA_ORDER_EQ) + o = stringOrder((const UA_String*)&p1->content.encoded.body, + (const UA_String*)&p2->content.encoded.body, NULL); + return o; + } + + case UA_EXTENSIONOBJECT_DECODED: + default: { + const UA_DataType *type1 = p1->content.decoded.type; + const UA_DataType *type2 = p1->content.decoded.type; + if(type1 != type2) + return ((uintptr_t)type1 < (uintptr_t)type2) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(!type1) + return UA_ORDER_EQ; + return orderJumpTable[type1->typeKind] + (p1->content.decoded.data, p2->content.decoded.data, type1); + } + } +} + +static UA_Order +arrayOrder(const void *p1, size_t p1Length, const void *p2, size_t p2Length, + const UA_DataType *type) { + if(p1Length != p2Length) + return (p1Length < p2Length) ? UA_ORDER_LESS : UA_ORDER_MORE; + /* For zero-length arrays, every pointer not NULL is considered a + * UA_EMPTY_ARRAY_SENTINEL. */ + if(p1 == p2) return UA_ORDER_EQ; + if(p1 == NULL) return UA_ORDER_LESS; + if(p2 == NULL) return UA_ORDER_MORE; + uintptr_t u1 = (uintptr_t)p1; + uintptr_t u2 = (uintptr_t)p2; + for(size_t i = 0; i < p1Length; i++) { + UA_Order o = orderJumpTable[type->typeKind]((const void*)u1, (const void*)u2, type); + if(o != UA_ORDER_EQ) + return o; + u1 += type->memSize; + u2 += type->memSize; + } + return UA_ORDER_EQ; +} + +static UA_Order +variantOrder(const UA_Variant *p1, const UA_Variant *p2, + const UA_DataType *type) { + if(p1->type != p2->type) + return ((uintptr_t)p1->type < (uintptr_t)p2->type) ? UA_ORDER_LESS : UA_ORDER_MORE; + + UA_Order o; + if(p1->type != NULL) { + /* Check if both variants are scalars or arrays */ + UA_Boolean s1 = UA_Variant_isScalar(p1); + UA_Boolean s2 = UA_Variant_isScalar(p2); + if(s1 != s2) + return s1 ? UA_ORDER_LESS : UA_ORDER_MORE; + if(s1) { + o = orderJumpTable[p1->type->typeKind](p1->data, p2->data, p1->type); + } else { + /* Mismatching array length? */ + if(p1->arrayLength != p2->arrayLength) + return (p1->arrayLength < p2->arrayLength) ? UA_ORDER_LESS : UA_ORDER_MORE; + o = arrayOrder(p1->data, p1->arrayLength, p2->data, p2->arrayLength, p1->type); + } + if(o != UA_ORDER_EQ) + return o; + } + + if(p1->arrayDimensionsSize != p2->arrayDimensionsSize) + return (p1->arrayDimensionsSize < p2->arrayDimensionsSize) ? + UA_ORDER_LESS : UA_ORDER_MORE; + o = UA_ORDER_EQ; + if(p1->arrayDimensionsSize > 0) + o = arrayOrder(p1->arrayDimensions, p1->arrayDimensionsSize, + p2->arrayDimensions, p2->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_UINT32]); + return o; +} + +static UA_Order +dataValueOrder(const UA_DataValue *p1, const UA_DataValue *p2, + const UA_DataType *type) { + /* Value */ + if(p1->hasValue != p2->hasValue) + return (!p1->hasValue) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasValue) { + UA_Order o = variantOrder(&p1->value, &p2->value, NULL); + if(o != UA_ORDER_EQ) + return o; + } + + /* Status */ + if(p1->hasStatus != p2->hasStatus) + return (!p1->hasStatus) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasStatus && p1->status != p2->status) + return (p1->status < p2->status) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* SourceTimestamp */ + if(p1->hasSourceTimestamp != p2->hasSourceTimestamp) + return (!p1->hasSourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasSourceTimestamp && p1->sourceTimestamp != p2->sourceTimestamp) + return (p1->sourceTimestamp < p2->sourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* ServerTimestamp */ + if(p1->hasServerTimestamp != p2->hasServerTimestamp) + return (!p1->hasServerTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasServerTimestamp && p1->serverTimestamp != p2->serverTimestamp) + return (p1->serverTimestamp < p2->serverTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* SourcePicoseconds */ + if(p1->hasSourcePicoseconds != p2->hasSourcePicoseconds) + return (!p1->hasSourcePicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasSourcePicoseconds && p1->sourcePicoseconds != p2->sourcePicoseconds) + return (p1->sourcePicoseconds < p2->sourcePicoseconds) ? + UA_ORDER_LESS : UA_ORDER_MORE; + + /* ServerPicoseconds */ + if(p1->hasServerPicoseconds != p2->hasServerPicoseconds) + return (!p1->hasServerPicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasServerPicoseconds && p1->serverPicoseconds != p2->serverPicoseconds) + return (p1->serverPicoseconds < p2->serverPicoseconds) ? + UA_ORDER_LESS : UA_ORDER_MORE; + + return UA_ORDER_EQ; +} + +static UA_Order +diagnosticInfoOrder(const UA_DiagnosticInfo *p1, const UA_DiagnosticInfo *p2, + const UA_DataType *type) { + /* SymbolicId */ + if(p1->hasSymbolicId != p2->hasSymbolicId) + return (!p1->hasSymbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasSymbolicId && p1->symbolicId != p2->symbolicId) + return (p1->symbolicId < p2->symbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* NamespaceUri */ + if(p1->hasNamespaceUri != p2->hasNamespaceUri) + return (!p1->hasNamespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasNamespaceUri && p1->namespaceUri != p2->namespaceUri) + return (p1->namespaceUri < p2->namespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* LocalizedText */ + if(p1->hasLocalizedText != p2->hasLocalizedText) + return (!p1->hasLocalizedText) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasLocalizedText && p1->localizedText != p2->localizedText) + return (p1->localizedText < p2->localizedText) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* Locale */ + if(p1->hasLocale != p2->hasLocale) + return (!p1->hasLocale) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasLocale && p1->locale != p2->locale) + return (p1->locale < p2->locale) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* AdditionalInfo */ + if(p1->hasAdditionalInfo != p2->hasAdditionalInfo) + return (!p1->hasAdditionalInfo) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasAdditionalInfo) { + UA_Order o = stringOrder(&p1->additionalInfo, &p2->additionalInfo, NULL); + if(o != UA_ORDER_EQ) + return o; + } + + /* InnerStatusCode */ + if(p1->hasInnerStatusCode != p2->hasInnerStatusCode) + return (!p1->hasInnerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasInnerStatusCode && p1->innerStatusCode != p2->innerStatusCode) + return (p1->innerStatusCode < p2->innerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* InnerDiagnosticInfo */ + if(p1->hasInnerDiagnosticInfo != p2->hasInnerDiagnosticInfo) + return (!p1->hasInnerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->innerDiagnosticInfo == p2->innerDiagnosticInfo) + return UA_ORDER_EQ; + if(!p1->innerDiagnosticInfo || !p2->innerDiagnosticInfo) + return (!p1->innerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE; + return diagnosticInfoOrder(p1->innerDiagnosticInfo, p2->innerDiagnosticInfo, NULL); +} + +static UA_Order +structureOrder(const void *p1, const void *p2, const UA_DataType *type) { + uintptr_t u1 = (uintptr_t)p1; + uintptr_t u2 = (uintptr_t)p2; + UA_Order o = UA_ORDER_EQ; + for(size_t i = 0; i < type->membersSize; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + u1 += m->padding; + u2 += m->padding; + if(!m->isOptional) { + if(!m->isArray) { + o = orderJumpTable[mt->typeKind]((const void *)u1, (const void *)u2, mt); + u1 += mt->memSize; + u2 += mt->memSize; + } else { + size_t size1 = *(size_t*)u1; + size_t size2 = *(size_t*)u2; + u1 += sizeof(size_t); + u2 += sizeof(size_t); + o = arrayOrder(*(void* const*)u1, size1, *(void* const*)u2, size2, mt); + u1 += sizeof(void*); + u2 += sizeof(void*); + } + } else { + if(!m->isArray) { + const void *pp1 = *(void* const*)u1; + const void *pp2 = *(void* const*)u2; + if(pp1 == pp2) { + o = UA_ORDER_EQ; + } else if(pp1 == NULL) { + o = UA_ORDER_LESS; + } else if(pp2 == NULL) { + o = UA_ORDER_MORE; + } else { + o = orderJumpTable[mt->typeKind](pp1, pp2, mt); + } + } else { + size_t sa1 = *(size_t*)u1; + size_t sa2 = *(size_t*)u2; + u1 += sizeof(size_t); + u2 += sizeof(size_t); + o = arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt); + } + u1 += sizeof(void*); + u2 += sizeof(void*); + } + + if(o != UA_ORDER_EQ) + break; + } + return o; +} + +static UA_Order +unionOrder(const void *p1, const void *p2, const UA_DataType *type) { + UA_UInt32 sel1 = *(const UA_UInt32 *)p1; + UA_UInt32 sel2 = *(const UA_UInt32 *)p2; + if(sel1 != sel2) + return (sel1 < sel2) ? UA_ORDER_LESS : UA_ORDER_MORE; + + if(sel1 == 0) { + return UA_ORDER_EQ; + } + + const UA_DataTypeMember *m = &type->members[sel1-1]; + const UA_DataType *mt = m->memberType; + + uintptr_t u1 = ((uintptr_t)p1) + m->padding; /* includes switchfield length */ + uintptr_t u2 = ((uintptr_t)p2) + m->padding; + if(m->isArray) { + size_t sa1 = *(size_t*)u1; + size_t sa2 = *(size_t*)u2; + u1 += sizeof(size_t); + u2 += sizeof(size_t); + return arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt); + } + return orderJumpTable[mt->typeKind]((const void*)u1, (const void*)u2, mt); +} + +static UA_Order +notImplementedOrder(const void *p1, const void *p2, const UA_DataType *type) { + return UA_ORDER_EQ; +} + +const +UA_orderSignature orderJumpTable[UA_DATATYPEKINDS] = { + (UA_orderSignature)booleanOrder, + (UA_orderSignature)sByteOrder, + (UA_orderSignature)byteOrder, + (UA_orderSignature)int16Order, + (UA_orderSignature)uInt16Order, + (UA_orderSignature)int32Order, + (UA_orderSignature)uInt32Order, + (UA_orderSignature)int64Order, + (UA_orderSignature)uInt64Order, + (UA_orderSignature)floatOrder, + (UA_orderSignature)doubleOrder, + (UA_orderSignature)stringOrder, + (UA_orderSignature)int64Order, /* DateTime */ + (UA_orderSignature)guidOrder, + (UA_orderSignature)stringOrder, /* ByteString */ + (UA_orderSignature)stringOrder, /* XmlElement */ + (UA_orderSignature)nodeIdOrder, + (UA_orderSignature)expandedNodeIdOrder, + (UA_orderSignature)uInt32Order, /* StatusCode */ + (UA_orderSignature)qualifiedNameOrder, + (UA_orderSignature)localizedTextOrder, + (UA_orderSignature)extensionObjectOrder, + (UA_orderSignature)dataValueOrder, + (UA_orderSignature)variantOrder, + (UA_orderSignature)diagnosticInfoOrder, + notImplementedOrder, /* Decimal, not implemented */ + (UA_orderSignature)uInt32Order, /* Enumeration */ + (UA_orderSignature)structureOrder, + (UA_orderSignature)structureOrder, /* Struct with Optional Fields*/ + (UA_orderSignature)unionOrder, /* Union*/ + notImplementedOrder /* BitfieldCluster, not implemented */ +}; + +UA_Order UA_order(const void *p1, const void *p2, const UA_DataType *type) { + return orderJumpTable[type->typeKind](p1, p2, type); +} + +/******************/ /* Array Handling */ /******************/ @@ -8821,6 +6928,93 @@ UA_Array_copy(const void *src, size_t size, return retval; } +UA_StatusCode +UA_Array_resize(void **p, size_t *size, size_t newSize, + const UA_DataType *type) { + if(*size == newSize) + return UA_STATUSCODE_GOOD; + + /* Empty array? */ + if(newSize == 0) { + UA_Array_delete(*p, *size, type); + *p = UA_EMPTY_ARRAY_SENTINEL; + *size = 0; + return UA_STATUSCODE_GOOD; + } + + /* Make a copy of the members that shall be removed. Realloc can fail during + * trimming. So we cannot clear the members already here. */ + void *deleteMembers = NULL; + if(newSize < *size && !type->pointerFree) { + size_t deleteSize = *size - newSize; + deleteMembers = UA_malloc(deleteSize * type->memSize); + if(!deleteMembers) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(deleteMembers, (void*)((uintptr_t)*p + (newSize * type->memSize)), + deleteSize * type->memSize); /* shallow copy */ + } + + void *oldP = *p; + if(oldP == UA_EMPTY_ARRAY_SENTINEL) + oldP = NULL; + + /* Realloc */ + void *newP = UA_realloc(oldP, newSize * type->memSize); + if(!newP) { + if(deleteMembers) + UA_free(deleteMembers); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Clear removed members or initialize the new ones. Note that deleteMembers + * depends on type->pointerFree. */ + if(newSize > *size) + memset((void*)((uintptr_t)newP + (*size * type->memSize)), 0, + (newSize - *size) * type->memSize); + else if(deleteMembers) + UA_Array_delete(deleteMembers, *size - newSize, type); + + /* Set the new array */ + *p = newP; + *size = newSize; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Array_append(void **p, size_t *size, void *newElem, + const UA_DataType *type) { + /* Resize the array */ + size_t oldSize = *size; + UA_StatusCode res = UA_Array_resize(p, size, oldSize+1, type); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Move the value */ + memcpy((void*)((uintptr_t)*p + (oldSize * type->memSize)), + newElem, type->memSize); + UA_init(newElem, type); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode UA_EXPORT +UA_Array_appendCopy(void **p, size_t *size, const void *newElem, + const UA_DataType *type) { + char scratch[512]; + if(type->memSize > 512) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Copy the value */ + UA_StatusCode res = UA_copy(newElem, (void*)scratch, type); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Append */ + res = UA_Array_append(p, size, (void*)scratch, type); + if(res != UA_STATUSCODE_GOOD) + UA_clear((void*)scratch, type); + return res; +} + void UA_Array_delete(void *p, size_t size, const UA_DataType *type) { if(!type->pointerFree) { @@ -8833,14 +7027,113 @@ UA_Array_delete(void *p, size_t size, const UA_DataType *type) { UA_free((void*)((uintptr_t)p & ~(uintptr_t)UA_EMPTY_ARRAY_SENTINEL)); } +#ifdef UA_ENABLE_TYPEDESCRIPTION UA_Boolean -UA_DataType_isNumeric(const UA_DataType *type) { - /* All data types between UA_TYPES_BOOLEAN and UA_TYPES_DOUBLE are numeric */ - for(size_t i = UA_TYPES_BOOLEAN; i <= UA_TYPES_DOUBLE; ++i) - if(&UA_TYPES[i] == type) +UA_DataType_getStructMember(const UA_DataType *type, const char *memberName, + size_t *outOffset, const UA_DataType **outMemberType, + UA_Boolean *outIsArray) { + if(type->typeKind != UA_DATATYPEKIND_STRUCTURE && + type->typeKind != UA_DATATYPEKIND_OPTSTRUCT) + return false; + + size_t offset = 0; + for(size_t i = 0; i < type->membersSize; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + offset += m->padding; + + if(strcmp(memberName, m->memberName) == 0) { + *outOffset = offset; + *outMemberType = mt; + *outIsArray = m->isArray; return true; + } + + if(!m->isOptional) { + if(!m->isArray) { + offset += mt->memSize; + } else { + offset += sizeof(size_t); + offset += sizeof(void*); + } + } else { /* field is optional */ + if(!m->isArray) { + offset += sizeof(void *); + } else { + offset += sizeof(size_t); + offset += sizeof(void *); + } + } + } + return false; } +#endif + +UA_Boolean +UA_DataType_isNumeric(const UA_DataType *type) { + switch(type->typeKind) { + case UA_DATATYPEKIND_SBYTE: + case UA_DATATYPEKIND_BYTE: + case UA_DATATYPEKIND_INT16: + case UA_DATATYPEKIND_UINT16: + case UA_DATATYPEKIND_INT32: + case UA_DATATYPEKIND_UINT32: + case UA_DATATYPEKIND_INT64: + case UA_DATATYPEKIND_UINT64: + case UA_DATATYPEKIND_FLOAT: + case UA_DATATYPEKIND_DOUBLE: + /* not implemented: UA_DATATYPEKIND_DECIMAL */ + return true; + default: + return false; + } +} + +UA_Int16 +UA_DataType_getPrecedence(const UA_DataType *type){ + //Defined in Part 4 Table 123 "Data Precedence Rules" + switch(type->typeKind) { + case UA_DATATYPEKIND_DOUBLE: + return 1; + case UA_DATATYPEKIND_FLOAT: + return 2; + case UA_DATATYPEKIND_INT64: + return 3; + case UA_DATATYPEKIND_UINT64: + return 4; + case UA_DATATYPEKIND_INT32: + return 5; + case UA_DATATYPEKIND_UINT32: + return 6; + case UA_DATATYPEKIND_STATUSCODE: + return 7; + case UA_DATATYPEKIND_INT16: + return 8; + case UA_DATATYPEKIND_UINT16: + return 9; + case UA_DATATYPEKIND_SBYTE: + return 10; + case UA_DATATYPEKIND_BYTE: + return 11; + case UA_DATATYPEKIND_BOOLEAN: + return 12; + case UA_DATATYPEKIND_GUID: + return 13; + case UA_DATATYPEKIND_STRING: + return 14; + case UA_DATATYPEKIND_EXPANDEDNODEID: + return 15; + case UA_DATATYPEKIND_NODEID: + return 16; + case UA_DATATYPEKIND_LOCALIZEDTEXT: + return 17; + case UA_DATATYPEKIND_QUALIFIEDNAME: + return 18; + default: + return -1; + } +} /**********************/ /* Parse NumericRange */ @@ -8913,13 +7206,14 @@ UA_NumericRange_parse(UA_NumericRange *range, const UA_String str) { if(retval == UA_STATUSCODE_GOOD && idx > 0) { range->dimensions = dimensions; range->dimensionsSize = idx; - } else + } else { UA_free(dimensions); + } return retval; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_types_encoding_binary.c" ***********************************/ +/**** amalgamated original file "/src/ua_types_encoding_binary.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -8927,7 +7221,7 @@ UA_NumericRange_parse(UA_NumericRange *range, const UA_String str) { * * Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner) * Copyright 2020 (c) Grigory Friedman - * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2014-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2014-2017 (c) Florian Palm * Copyright 2014-2016 (c) Sten Grüner * Copyright 2014 (c) Leon Urbas @@ -8949,12 +7243,10 @@ UA_NumericRange_parse(UA_NumericRange *range, const UA_String str) { * data types and generic functions that operate on all types and arrays. This * requires the type description from a UA_DataType structure. * - * Encoding Context - * ^^^^^^^^^^^^^^^^ - * If possible, the encoding context is stored in a thread-local variable to - * speed up encoding. If thread-local variables are not supported, the context - * is "looped through" every method call. The ``_``-macro accesses either the - * thread-local or the "looped through" context . */ + * Breaking a message up into chunks is integrated with the encoding. When the + * end of a buffer is reached, a callback is executed that sends the current + * buffer as a chunk and exchanges the encoding buffer "underneath" the ongoing + * encoding. This reduces the RAM requirements and unnecessary copying. */ /* Part 6 §5.1.5: Decoders shall support at least 100 nesting levels */ #define UA_ENCODING_MAX_RECURSION 100 @@ -9000,11 +7292,6 @@ extern const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS]; extern const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS]; extern const calcSizeBinarySignature calcSizeBinaryJumpTable[UA_DATATYPEKINDS]; -/* Breaking a message up into chunks is integrated with the encoding. When the - * end of a buffer is reached, a callback is executed that sends the current - * buffer as a chunk and exchanges the encoding buffer "underneath" the ongoing - * encoding. This reduces the RAM requirements and unnecessary copying. */ - /* Send the current chunk and replace the buffer */ static status exchangeBuffer(Ctx *ctx) { if(!ctx->exchangeBufferCallback) @@ -9018,10 +7305,11 @@ static status encodeWithExchangeBuffer(const void *ptr, const UA_DataType *type, Ctx *ctx) { u8 *oldpos = ctx->pos; /* Last known good position */ #ifndef NDEBUG - /* Ensure that the buffer was not exchanged AND BADENCODINGLIMITSEXCEEDED - * was returned. If that were the case, oldpos would be invalid. That means, - * a type encoding must not return BADENCODINGLIMITSEXCEEDED after the - * buffer could have been exchanged. */ + /* We have to ensure that the buffer was not exchanged AND + * BADENCODINGLIMITSEXCEEDED was returned. If that were the case, oldpos + * would be invalid. That means, a type encoding must never return + * BADENCODINGLIMITSEXCEEDED once the buffer could have been exchanged. This + * is achieved by the use of encodeWithExchangeBuffer. */ const u8 *oldend = ctx->end; (void)oldend; /* For compilers who don't understand NDEBUG... */ #endif @@ -9030,8 +7318,7 @@ encodeWithExchangeBuffer(const void *ptr, const UA_DataType *type, Ctx *ctx) { UA_assert(ctx->end == oldend); ctx->pos = oldpos; /* Set to the last known good position and exchange */ ret = exchangeBuffer(ctx); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); ret = encodeBinaryJumpTable[type->typeKind](ptr, type, ctx); } return ret; @@ -9097,16 +7384,14 @@ UA_decode64(const u8 buf[8], u64 *v) { /* Note that sizeof(bool) != 1 on some platforms. Overlayable integer encoding * is disabled in those cases. */ ENCODE_BINARY(Boolean) { - if(ctx->pos + 1 > ctx->end) - return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); *ctx->pos = *(const u8*)src; ++ctx->pos; return UA_STATUSCODE_GOOD; } DECODE_BINARY(Boolean) { - if(ctx->pos + 1 > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR); *dst = (*ctx->pos > 0) ? true : false; ++ctx->pos; return UA_STATUSCODE_GOOD; @@ -9114,16 +7399,16 @@ DECODE_BINARY(Boolean) { /* Byte */ ENCODE_BINARY(Byte) { - if(ctx->pos + sizeof(u8) > ctx->end) - return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + UA_CHECK(ctx->pos + sizeof(u8) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); *ctx->pos = *(const u8*)src; ++ctx->pos; return UA_STATUSCODE_GOOD; } DECODE_BINARY(Byte) { - if(ctx->pos + sizeof(u8) > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + sizeof(u8) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); *dst = *ctx->pos; ++ctx->pos; return UA_STATUSCODE_GOOD; @@ -9131,8 +7416,8 @@ DECODE_BINARY(Byte) { /* UInt16 */ ENCODE_BINARY(UInt16) { - if(ctx->pos + sizeof(u16) > ctx->end) - return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + UA_CHECK(ctx->pos + sizeof(u16) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); #if UA_BINARY_OVERLAYABLE_INTEGER memcpy(ctx->pos, src, sizeof(u16)); #else @@ -9143,8 +7428,8 @@ ENCODE_BINARY(UInt16) { } DECODE_BINARY(UInt16) { - if(ctx->pos + sizeof(u16) > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + sizeof(u16) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); #if UA_BINARY_OVERLAYABLE_INTEGER memcpy(dst, ctx->pos, sizeof(u16)); #else @@ -9156,8 +7441,8 @@ DECODE_BINARY(UInt16) { /* UInt32 */ ENCODE_BINARY(UInt32) { - if(ctx->pos + sizeof(u32) > ctx->end) - return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + UA_CHECK(ctx->pos + sizeof(u32) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); #if UA_BINARY_OVERLAYABLE_INTEGER memcpy(ctx->pos, src, sizeof(u32)); #else @@ -9168,8 +7453,8 @@ ENCODE_BINARY(UInt32) { } DECODE_BINARY(UInt32) { - if(ctx->pos + sizeof(u32) > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + sizeof(u32) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); #if UA_BINARY_OVERLAYABLE_INTEGER memcpy(dst, ctx->pos, sizeof(u32)); #else @@ -9181,8 +7466,8 @@ DECODE_BINARY(UInt32) { /* UInt64 */ ENCODE_BINARY(UInt64) { - if(ctx->pos + sizeof(u64) > ctx->end) - return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + UA_CHECK(ctx->pos + sizeof(u64) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); #if UA_BINARY_OVERLAYABLE_INTEGER memcpy(ctx->pos, src, sizeof(u64)); #else @@ -9193,8 +7478,8 @@ ENCODE_BINARY(UInt64) { } DECODE_BINARY(UInt64) { - if(ctx->pos + sizeof(u64) > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + sizeof(u64) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); #if UA_BINARY_OVERLAYABLE_INTEGER memcpy(dst, ctx->pos, sizeof(u64)); #else @@ -9244,7 +7529,7 @@ static long double unpack754(uint64_t i, unsigned bits, unsigned expbits) { unsigned significandbits = bits - expbits - 1; long double result = (long double)(i&(uint64_t)((1LL<<significandbits)-1)); - result /= (1LL<<significandbits); + result /= (long double)(1LL<<significandbits); result += 1.0f; unsigned bias = (unsigned)(1<<(expbits-1)) - 1; long long shift = (long long)((i>>significandbits) & (uint64_t)((1LL<<expbits)-1)) - bias; @@ -9306,8 +7591,7 @@ ENCODE_BINARY(Double) { DECODE_BINARY(Double) { u64 decoded; status ret = DECODE_DIRECT(&decoded, UInt64); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); if(decoded == 0) *dst = 0.0; else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0; else if(decoded == DOUBLE_INF) *dst = INFINITY; @@ -9333,8 +7617,8 @@ Array_encodeBinaryOverlayable(uintptr_t ptr, size_t memSize, Ctx *ctx) { ctx->pos += possible; ptr += possible; status ret = exchangeBuffer(ctx); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); memSize -= possible; } @@ -9351,10 +7635,9 @@ Array_encodeBinaryComplex(uintptr_t ptr, size_t length, for(size_t i = 0; i < length; ++i) { status ret = encodeWithExchangeBuffer((const void*)ptr, type, ctx); ptr += type->memSize; - if(ret != UA_STATUSCODE_GOOD) - return ret; /* Unrecoverable fail */ + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); /* Unrecoverable fail */ } - return UA_STATUSCODE_GOOD; } @@ -9372,14 +7655,15 @@ Array_encodeBinary(const void *src, size_t length, const UA_DataType *type, Ctx /* Encode the array length */ status ret = encodeWithExchangeBuffer(&signed_length, &UA_TYPES[UA_TYPES_INT32], ctx); UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); - if(ret != UA_STATUSCODE_GOOD || length == 0) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Encode the content */ - if(type->overlayable) - ret = Array_encodeBinaryOverlayable((uintptr_t)src, length * type->memSize, ctx); - else - ret = Array_encodeBinaryComplex((uintptr_t)src, length, type, ctx); + if(length > 0) { + if(type->overlayable) + ret = Array_encodeBinaryOverlayable((uintptr_t)src, length * type->memSize, ctx); + else + ret = Array_encodeBinaryComplex((uintptr_t)src, length, type, ctx); + } UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); return ret; } @@ -9390,8 +7674,7 @@ Array_decodeBinary(void *UA_RESTRICT *UA_RESTRICT dst, size_t *out_length, /* Decode the length */ i32 signed_length; status ret = DECODE_DIRECT(&signed_length, UInt32); /* Int32 */ - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Return early for empty arrays */ if(signed_length <= 0) { @@ -9407,21 +7690,17 @@ Array_decodeBinary(void *UA_RESTRICT *UA_RESTRICT dst, size_t *out_length, * is too small for the array length. This prevents the allocation of very * long arrays for bogus messages.*/ size_t length = (size_t)signed_length; - if(ctx->pos + ((type->memSize * length) / 32) > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + ((type->memSize * length) / 32) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); /* Allocate memory */ *dst = UA_calloc(length, type->memSize); - if(!*dst) - return UA_STATUSCODE_BADOUTOFMEMORY; + UA_CHECK_MEM(*dst, return UA_STATUSCODE_BADOUTOFMEMORY); if(type->overlayable) { /* memcpy overlayable array */ - if(ctx->end < ctx->pos + (type->memSize * length)) { - UA_free(*dst); - *dst = NULL; - return UA_STATUSCODE_BADDECODINGERROR; - } + UA_CHECK(ctx->pos + (type->memSize * length) <= ctx->end, + UA_free(*dst); *dst = NULL; return UA_STATUSCODE_BADDECODINGERROR); memcpy(*dst, ctx->pos, type->memSize * length); ctx->pos += type->memSize * length; } else { @@ -9429,12 +7708,8 @@ Array_decodeBinary(void *UA_RESTRICT *UA_RESTRICT dst, size_t *out_length, uintptr_t ptr = (uintptr_t)*dst; for(size_t i = 0; i < length; ++i) { ret = decodeBinaryJumpTable[type->typeKind]((void*)ptr, type, ctx); - if(ret != UA_STATUSCODE_GOOD) { - /* +1 because last element is also already initialized */ - UA_Array_delete(*dst, i+1, type); - *dst = NULL; - return ret; - } + UA_CHECK_STATUS(ret, /* +1 because last element is also already initialized */ + UA_Array_delete(*dst, i+1, type); *dst = NULL; return ret); ptr += type->memSize; } } @@ -9460,8 +7735,8 @@ ENCODE_BINARY(Guid) { ret |= ENCODE_DIRECT(&src->data1, UInt32); ret |= ENCODE_DIRECT(&src->data2, UInt16); ret |= ENCODE_DIRECT(&src->data3, UInt16); - if(ctx->pos + (8*sizeof(u8)) > ctx->end) - return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + UA_CHECK(ctx->pos + (8*sizeof(u8)) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); memcpy(ctx->pos, src->data4, 8*sizeof(u8)); ctx->pos += 8; return ret; @@ -9472,8 +7747,8 @@ DECODE_BINARY(Guid) { ret |= DECODE_DIRECT(&dst->data1, UInt32); ret |= DECODE_DIRECT(&dst->data2, UInt16); ret |= DECODE_DIRECT(&dst->data3, UInt16); - if(ctx->pos + (8*sizeof(u8)) > ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + (8*sizeof(u8)) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); memcpy(dst->data4, ctx->pos, 8*sizeof(u8)); ctx->pos += 8; return ret; @@ -9516,8 +7791,8 @@ NodeId_encodeBinaryWithEncodingMask(UA_NodeId const *src, u8 encoding, Ctx *ctx) encoding |= (u8)UA_NODEIDTYPE_STRING; ret |= ENCODE_DIRECT(&encoding, Byte); ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); + /* Can exchange the buffer */ ret = ENCODE_DIRECT(&src->identifier.string, String); UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); break; @@ -9531,8 +7806,8 @@ NodeId_encodeBinaryWithEncodingMask(UA_NodeId const *src, u8 encoding, Ctx *ctx) encoding |= (u8)UA_NODEIDTYPE_BYTESTRING; ret |= ENCODE_DIRECT(&encoding, Byte); ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); + /* Can exchange the buffer */ ret = ENCODE_DIRECT(&src->identifier.byteString, String); /* ByteString */ UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); break; @@ -9552,8 +7827,7 @@ DECODE_BINARY(NodeId) { /* Decode the encoding bitfield */ status ret = DECODE_DIRECT(&encodingByte, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Filter out the bits used only for ExpandedNodeIds */ encodingByte &= (u8)~(u8)(UA_EXPANDEDNODEID_SERVERINDEX_FLAG | @@ -9610,17 +7884,17 @@ ENCODE_BINARY(ExpandedNodeId) { if(src->serverIndex > 0) encoding |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG; - /* Encode the NodeId */ + /* Encode the NodeId. Can exchange the buffer. */ status ret = NodeId_encodeBinaryWithEncodingMask(&src->nodeId, encoding, ctx); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); - /* Encode the namespace. */ + /* Encode the namespace. Internally uses encodeWithExchangeBuffer + * everywhere. So it will never return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */ if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL) { ret = ENCODE_DIRECT(&src->namespaceUri, String); UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); } /* Encode the serverIndex */ @@ -9632,8 +7906,7 @@ ENCODE_BINARY(ExpandedNodeId) { DECODE_BINARY(ExpandedNodeId) { /* Decode the encoding mask */ - if(ctx->pos >= ctx->end) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR); u8 encoding = *ctx->pos; /* Decode the NodeId */ @@ -9654,8 +7927,8 @@ DECODE_BINARY(ExpandedNodeId) { /* QualifiedName */ ENCODE_BINARY(QualifiedName) { status ret = ENCODE_DIRECT(&src->namespaceIndex, UInt16); - if(ret != UA_STATUSCODE_GOOD) - return ret; + /* Must check here so we can exchange the buffer in the string encoding */ + UA_CHECK_STATUS(ret, return ret); ret |= ENCODE_DIRECT(&src->name, String); return ret; } @@ -9680,8 +7953,8 @@ ENCODE_BINARY(LocalizedText) { /* Encode the encoding byte */ status ret = ENCODE_DIRECT(&encoding, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + /* Must check here so we can exchange the buffer in the string encoding */ + UA_CHECK_STATUS(ret, return ret); /* Encode the strings */ if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE) @@ -9709,23 +7982,21 @@ DECODE_BINARY(LocalizedText) { * possible to reuse UA_findDataType */ static const UA_DataType * UA_findDataTypeByBinaryInternal(const UA_NodeId *typeId, Ctx *ctx) { - /* We only store a numeric identifier for the encoding nodeid of data types */ - if(typeId->identifierType != UA_NODEIDTYPE_NUMERIC) - return NULL; - - /* Always look in built-in types first - * (may contain data types from all namespaces) */ - for(size_t i = 0; i < UA_TYPES_COUNT; ++i) { - if(UA_TYPES[i].binaryEncodingId == typeId->identifier.numeric && - UA_TYPES[i].typeId.namespaceIndex == typeId->namespaceIndex) - return &UA_TYPES[i]; + /* Always look in the built-in types first. Assume that only numeric + * identifiers are used for the builtin types. (They may contain data types + * from all namespaces though.) */ + if(typeId->identifierType == UA_NODEIDTYPE_NUMERIC) { + for(size_t i = 0; i < UA_TYPES_COUNT; ++i) { + if(UA_TYPES[i].binaryEncodingId.identifier.numeric == typeId->identifier.numeric && + UA_TYPES[i].binaryEncodingId.namespaceIndex == typeId->namespaceIndex) + return &UA_TYPES[i]; + } } const UA_DataTypeArray *customTypes = ctx->customTypes; while(customTypes) { for(size_t i = 0; i < customTypes->typesSize; ++i) { - if(customTypes->types[i].binaryEncodingId == typeId->identifier.numeric && - customTypes->types[i].typeId.namespaceIndex == typeId->namespaceIndex) + if(UA_NodeId_equal(typeId, &customTypes->types[i].binaryEncodingId)) return &customTypes->types[i]; } customTypes = customTypes->next; @@ -9747,18 +8018,19 @@ ENCODE_BINARY(ExtensionObject) { /* No content or already encoded content. */ if(encoding <= UA_EXTENSIONOBJECT_ENCODED_XML) { + /* Can exchange the buffer */ status ret = ENCODE_DIRECT(&src->content.encoded.typeId, NodeId); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); ret = encodeWithExchangeBuffer(&encoding, &UA_TYPES[UA_TYPES_BYTE], ctx); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); switch(src->encoding) { case UA_EXTENSIONOBJECT_ENCODED_NOBODY: break; case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: case UA_EXTENSIONOBJECT_ENCODED_XML: - ret = ENCODE_DIRECT(&src->content.encoded.body, String); /* ByteString */ + /* ByteString in disguise. Array encoding can exchange the buffer */ + ret = ENCODE_DIRECT(&src->content.encoded.body, String); break; default: ret = UA_STATUSCODE_BADINTERNALERROR; @@ -9771,37 +8043,35 @@ ENCODE_BINARY(ExtensionObject) { if(!src->content.decoded.type || !src->content.decoded.data) return UA_STATUSCODE_BADENCODINGERROR; - /* Write the NodeId for the binary encoded type. The NodeId is always - * numeric, so no buffer replacement is taking place. */ - UA_NodeId typeId = src->content.decoded.type->typeId; - if(typeId.identifierType != UA_NODEIDTYPE_NUMERIC) - return UA_STATUSCODE_BADENCODINGERROR; - typeId.identifier.numeric = src->content.decoded.type->binaryEncodingId; - status ret = ENCODE_DIRECT(&typeId, NodeId); - UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); - if(ret != UA_STATUSCODE_GOOD) - return ret; + /* Write the NodeId for the binary encoded type. This could perform a buffer + * exchange, but can also return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */ + status ret = ENCODE_DIRECT(&src->content.decoded.type->binaryEncodingId, NodeId); + UA_CHECK_STATUS(ret, return ret); /* Encode the encoding byte */ encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; - ret |= ENCODE_DIRECT(&encoding, Byte); + ret = encodeWithExchangeBuffer(&encoding, &UA_TYPES[UA_TYPES_BYTE], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); /* Encode the content length */ const UA_DataType *contentType = src->content.decoded.type; size_t len = UA_calcSizeBinary(src->content.decoded.data, contentType); - if(len > UA_INT32_MAX) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(len <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR); i32 signed_len = (i32)len; - ret |= ENCODE_DIRECT(&signed_len, UInt32); /* Int32 */ - if(ret != UA_STATUSCODE_GOOD) - return ret; + ret = encodeWithExchangeBuffer(&signed_len, &UA_TYPES[UA_TYPES_INT32], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); /* Encode the content */ - return encodeWithExchangeBuffer(src->content.decoded.data, contentType, ctx); + ret = encodeWithExchangeBuffer(src->content.decoded.data, contentType, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; } static status -ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *typeId, Ctx *ctx) { +ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *typeId, + Ctx *ctx) { /* Lookup the datatype */ const UA_DataType *type = UA_findDataTypeByBinaryInternal(typeId, ctx); @@ -9814,8 +8084,7 @@ ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *ty /* Allocate memory */ dst->content.decoded.data = UA_new(type); - if(!dst->content.decoded.data) - return UA_STATUSCODE_BADOUTOFMEMORY; + UA_CHECK_MEM(dst->content.decoded.data, return UA_STATUSCODE_BADOUTOFMEMORY); /* Jump over the length field (TODO: check if the decoded length matches) */ ctx->pos += 4; @@ -9828,24 +8097,18 @@ ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *ty DECODE_BINARY(ExtensionObject) { u8 encoding = 0; - UA_NodeId binTypeId; /* Can contain a string nodeid. But no corresponding - * type is then found in open62541. We only store - * numerical nodeids of the binary encoding identifier. - * The extenionobject will be decoded to contain a - * binary blob. */ + UA_NodeId binTypeId; UA_NodeId_init(&binTypeId); + status ret = UA_STATUSCODE_GOOD; ret |= DECODE_DIRECT(&binTypeId, NodeId); ret |= DECODE_DIRECT(&encoding, Byte); - if(ret != UA_STATUSCODE_GOOD) { - UA_NodeId_clear(&binTypeId); - return ret; - } + UA_CHECK_STATUS(ret, UA_NodeId_clear(&binTypeId); return ret); switch(encoding) { case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: ret = ExtensionObject_decodeBinaryContent(dst, &binTypeId, ctx); - UA_NodeId_deleteMembers(&binTypeId); + UA_NodeId_clear(&binTypeId); break; case UA_EXTENSIONOBJECT_ENCODED_NOBODY: dst->encoding = (UA_ExtensionObjectEncoding)encoding; @@ -9856,8 +8119,7 @@ DECODE_BINARY(ExtensionObject) { dst->encoding = (UA_ExtensionObjectEncoding)encoding; dst->content.encoded.typeId = binTypeId; /* move to dst */ ret = DECODE_DIRECT(&dst->content.encoded.body, String); /* ByteString */ - if(ret != UA_STATUSCODE_GOOD) - UA_NodeId_clear(&dst->content.encoded.typeId); + UA_CHECK_STATUS(ret, UA_NodeId_clear(&dst->content.encoded.typeId)); break; default: UA_NodeId_clear(&binTypeId); @@ -9878,13 +8140,11 @@ Variant_encodeBinaryWrapExtensionObject(const UA_Variant *src, /* Encode the array length if required */ status ret = UA_STATUSCODE_GOOD; if(isArray) { - if(src->arrayLength > UA_INT32_MAX) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(src->arrayLength <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR); length = src->arrayLength; i32 encodedLength = (i32)src->arrayLength; ret = ENCODE_DIRECT(&encodedLength, UInt32); /* Int32 */ - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); } /* Set up the ExtensionObject */ @@ -9899,6 +8159,7 @@ Variant_encodeBinaryWrapExtensionObject(const UA_Variant *src, for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) { eo.content.decoded.data = (void*)ptr; ret = encodeWithExchangeBuffer(&eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); ptr += memSize; } return ret; @@ -9937,17 +8198,21 @@ ENCODE_BINARY(Variant) { /* Encode the encoding byte */ status ret = ENCODE_DIRECT(&encoding, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); - /* Encode the content */ - if(!isBuiltin && !isEnum) + /* Encode the content. This can exchange the buffer. */ + if(!isBuiltin && !isEnum) { + /* This could return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. But we + * have not exchanged the buffer so far. */ ret = Variant_encodeBinaryWrapExtensionObject(src, isArray, ctx); - else if(!isArray) + } else if(!isArray) { ret = encodeWithExchangeBuffer(src->data, src->type, ctx); - else + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + } else { ret = Array_encodeBinary(src->data, src->arrayLength, src->type, ctx); - UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + } + UA_CHECK_STATUS(ret, return ret); /* Encode the array dimensions */ if(hasDimensions && ret == UA_STATUSCODE_GOOD) @@ -9967,16 +8232,12 @@ Variant_decodeBinaryUnwrapExtensionObject(UA_Variant *dst, Ctx *ctx) { UA_NodeId typeId; UA_NodeId_init(&typeId); status ret = DECODE_DIRECT(&typeId, NodeId); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Decode the EncodingByte */ u8 encoding; ret = DECODE_DIRECT(&encoding, Byte); - if(ret != UA_STATUSCODE_GOOD) { - UA_NodeId_clear(&typeId); - return ret; - } + UA_CHECK_STATUS(ret, UA_NodeId_clear(&typeId); return ret); /* Search for the datatype. Default to ExtensionObject. */ if(encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING && @@ -9987,13 +8248,12 @@ Variant_decodeBinaryUnwrapExtensionObject(UA_Variant *dst, Ctx *ctx) { /* Reset and decode as ExtensionObject */ dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]; ctx->pos = old_pos; - UA_NodeId_clear(&typeId); } + UA_NodeId_clear(&typeId); /* Allocate memory */ dst->data = UA_new(dst->type); - if(!dst->data) - return UA_STATUSCODE_BADOUTOFMEMORY; + UA_CHECK_MEM(dst->data, return UA_STATUSCODE_BADOUTOFMEMORY); /* Decode the content */ return decodeBinaryJumpTable[dst->type->typeKind](dst->data, dst->type, ctx); @@ -10004,8 +8264,7 @@ DECODE_BINARY(Variant) { /* Decode the encoding byte */ u8 encodingByte; status ret = DECODE_DIRECT(&encodingByte, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Return early for an empty variant (was already _inited) */ if(encodingByte == 0) @@ -10019,17 +8278,15 @@ DECODE_BINARY(Variant) { * for types up to DiagnsticInfo equals to the index in the encoding * byte. */ size_t typeKind = (size_t)((encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1); - if(typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO, return UA_STATUSCODE_BADDECODINGERROR); /* A variant cannot contain a variant. But it can contain an array of * variants */ - if(typeKind == UA_DATATYPEKIND_VARIANT && !isArray) - return UA_STATUSCODE_BADDECODINGERROR; + UA_CHECK(typeKind != UA_DATATYPEKIND_VARIANT || isArray, + return UA_STATUSCODE_BADDECODINGERROR); /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; /* Decode the content */ @@ -10038,10 +8295,7 @@ DECODE_BINARY(Variant) { ret = Array_decodeBinary(&dst->data, &dst->arrayLength, dst->type, ctx); } else if(typeKind != UA_DATATYPEKIND_EXTENSIONOBJECT) { dst->data = UA_new(dst->type); - if(!dst->data) { - ctx->depth--; - return UA_STATUSCODE_BADOUTOFMEMORY; - } + UA_CHECK_MEM(dst->data, ctx->depth--; return UA_STATUSCODE_BADOUTOFMEMORY); ret = decodeBinaryJumpTable[typeKind](dst->data, dst->type, ctx); } else { ret = Variant_decodeBinaryUnwrapExtensionObject(dst, ctx); @@ -10068,8 +8322,7 @@ ENCODE_BINARY(DataValue) { /* Encode the encoding byte */ status ret = ENCODE_DIRECT(&encodingMask, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Encode the variant. */ if(src->hasValue) { @@ -10098,12 +8351,10 @@ DECODE_BINARY(DataValue) { /* Decode the encoding mask */ u8 encodingMask; status ret = DECODE_DIRECT(&encodingMask, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; /* Decode the content */ @@ -10137,7 +8388,6 @@ DECODE_BINARY(DataValue) { } ctx->depth--; - return ret; } @@ -10149,8 +8399,9 @@ ENCODE_BINARY(DiagnosticInfo) { encodingMask |= (u8)(src->hasLocalizedText << 2u); encodingMask |= (u8)(src->hasLocale << 3u); encodingMask |= (u8)(src->hasAdditionalInfo << 4u); - encodingMask |= (u8)(src->hasInnerDiagnosticInfo << 5u); - + encodingMask |= (u8)(src->hasInnerStatusCode << 5u); + encodingMask |= (u8)(src->hasInnerDiagnosticInfo << 6u); + /* Encode the numeric content */ status ret = ENCODE_DIRECT(&encodingMask, Byte); if(src->hasSymbolicId) @@ -10164,24 +8415,26 @@ ENCODE_BINARY(DiagnosticInfo) { if(ret != UA_STATUSCODE_GOOD) return ret; - /* Encode the additional info */ + /* Encode the additional info. Can exchange the buffer. */ if(src->hasAdditionalInfo) { ret = ENCODE_DIRECT(&src->additionalInfo, String); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); } /* Encode the inner status code */ if(src->hasInnerStatusCode) { ret = encodeWithExchangeBuffer(&src->innerStatusCode, &UA_TYPES[UA_TYPES_UINT32], ctx); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); } /* Encode the inner diagnostic info */ - if(src->hasInnerDiagnosticInfo) + if(src->hasInnerDiagnosticInfo) { ret = encodeWithExchangeBuffer(src->innerDiagnosticInfo, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + } return ret; } @@ -10190,8 +8443,7 @@ DECODE_BINARY(DiagnosticInfo) { /* Decode the encoding mask */ u8 encodingMask; status ret = DECODE_DIRECT(&encodingMask, Byte); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); /* Decode the content */ if(encodingMask & 0x01u) { @@ -10222,13 +8474,12 @@ DECODE_BINARY(DiagnosticInfo) { /* innerDiagnosticInfo is allocated on the heap */ dst->innerDiagnosticInfo = (UA_DiagnosticInfo*) UA_calloc(1, sizeof(UA_DiagnosticInfo)); - if(!dst->innerDiagnosticInfo) - return UA_STATUSCODE_BADOUTOFMEMORY; + UA_CHECK_MEM(dst->innerDiagnosticInfo, return UA_STATUSCODE_BADOUTOFMEMORY); dst->hasInnerDiagnosticInfo = true; /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo); @@ -10237,20 +8488,23 @@ DECODE_BINARY(DiagnosticInfo) { return ret; } +/********************/ +/* Structured Types */ +/********************/ + static status encodeBinaryStruct(const void *src, const UA_DataType *type, Ctx *ctx) { /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; /* Loop over members */ uintptr_t ptr = (uintptr_t)src; status ret = UA_STATUSCODE_GOOD; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; for(size_t i = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) { const UA_DataTypeMember *m = &type->members[i]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptr += m->padding; /* Array. Buffer-exchange is done inside Array_encodeBinary if required. */ @@ -10258,15 +8512,16 @@ encodeBinaryStruct(const void *src, const UA_DataType *type, Ctx *ctx) { const size_t length = *((const size_t*)ptr); ptr += sizeof(size_t); ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, mt, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); ptr += sizeof(void*); continue; } /* Scalar */ ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); ptr += mt->memSize; } - UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); ctx->depth--; return ret; @@ -10279,15 +8534,13 @@ encodeBinaryStructWithOptFields(const void *src, const UA_DataType *type, Ctx *c return UA_STATUSCODE_BADENCODINGERROR; ctx->depth++; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; - /* Creating the encoding mask, marking the available optional fields */ uintptr_t ptr = (uintptr_t)src; size_t optFieldCounter = 0; UA_UInt32 encodingMask = 0; for(size_t j = 0; j < type->membersSize; ++j) { const UA_DataTypeMember *m = &type->members[j]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptr += m->padding; if(m->isOptional) { if(m->isArray) @@ -10304,17 +8557,14 @@ encodeBinaryStructWithOptFields(const void *src, const UA_DataType *type, Ctx *c } /* Encode the mask */ - status ret = UInt32_encodeBinary(&encodingMask, &UA_TYPES[UA_TYPES_UINT32], ctx); - if(ret != UA_STATUSCODE_GOOD) { - ctx->depth--; - return ret; - } + status ret = ENCODE_DIRECT(&encodingMask, UInt32); + UA_CHECK_STATUS(ret, ctx->depth--; return ret); /* Loop over members */ ptr = (uintptr_t)src; - for(size_t i = 0, o = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) { + for(size_t i = 0, o = 0; i < type->membersSize && UA_LIKELY(ret == UA_STATUSCODE_GOOD); ++i) { const UA_DataTypeMember *m = &type->members[i]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptr += m->padding; if(m->isOptional) { @@ -10357,22 +8607,32 @@ encodeBinaryStructWithOptFields(const void *src, const UA_DataType *type, Ctx *c static status encodeBinaryUnion(const void *src, const UA_DataType *type, Ctx *ctx) { /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; + /* Encode the selection */ const UA_UInt32 selection = *(const UA_UInt32*)src; - status ret = ENCODE_DIRECT(src, UInt32); - if(ret != UA_STATUSCODE_GOOD || selection == 0) { + status ret = ENCODE_DIRECT(&selection, UInt32); + if(UA_UNLIKELY(ret != UA_STATUSCODE_GOOD) || selection == 0) { ctx->depth--; return ret; } - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; + /* Select the member */ const UA_DataTypeMember *m = &type->members[selection-1]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; - uintptr_t ptr = ((uintptr_t)src) + UA_TYPES[UA_TYPES_UINT32].memSize + m->padding; - ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx); + const UA_DataType *mt = m->memberType; + + /* Encode the member */ + uintptr_t ptr = ((uintptr_t)src) + m->padding; /* includes the switchfield length */ + if(!m->isArray) { + ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx); + } else { + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, mt, ctx); + } + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); ctx->depth--; @@ -10385,10 +8645,6 @@ encodeBinaryNotImplemented(const void *src, const UA_DataType *type, Ctx *ctx) { return UA_STATUSCODE_BADNOTIMPLEMENTED; } -/********************/ -/* Structured Types */ -/********************/ - const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS] = { (encodeBinarySignature)Boolean_encodeBinary, (encodeBinarySignature)Byte_encodeBinary, /* SByte */ @@ -10424,9 +8680,10 @@ const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS] = { }; status -UA_encodeBinary(const void *src, const UA_DataType *type, - u8 **bufPos, const u8 **bufEnd, - UA_exchangeEncodeBuffer exchangeCallback, void *exchangeHandle) { +UA_encodeBinaryInternal(const void *src, const UA_DataType *type, + u8 **bufPos, const u8 **bufEnd, + UA_exchangeEncodeBuffer exchangeCallback, + void *exchangeHandle) { /* Set up the context */ Ctx ctx; ctx.pos = *bufPos; @@ -10435,8 +8692,7 @@ UA_encodeBinary(const void *src, const UA_DataType *type, ctx.exchangeBufferCallback = exchangeCallback; ctx.exchangeBufferCallbackHandle = exchangeHandle; - if(!ctx.pos) - return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_CHECK_MEM(ctx.pos, return UA_STATUSCODE_BADINVALIDARGUMENT); /* Encode */ status ret = encodeWithExchangeBuffer(src, type, &ctx); @@ -10449,6 +8705,34 @@ UA_encodeBinary(const void *src, const UA_DataType *type, return ret; } +UA_StatusCode +UA_encodeBinary(const void *p, const UA_DataType *type, + UA_ByteString *outBuf) { + /* Allocate buffer */ + UA_Boolean allocated = false; + status res = UA_STATUSCODE_GOOD; + if(outBuf->length == 0) { + size_t len = UA_calcSizeBinary(p, type); + res = UA_ByteString_allocBuffer(outBuf, len); + if(res != UA_STATUSCODE_GOOD) + return res; + allocated = true; + } + + /* Encode */ + u8 *pos = outBuf->data; + const u8 *posEnd = &outBuf->data[outBuf->length]; + res = UA_encodeBinaryInternal(p, type, &pos, &posEnd, NULL, NULL); + + /* Clean up */ + if(res == UA_STATUSCODE_GOOD) { + outBuf->length = (size_t)((uintptr_t)pos - (uintptr_t)outBuf->data); + } else if(allocated) { + UA_ByteString_clear(outBuf); + } + return res; +} + static status decodeBinaryNotImplemented(void *dst, const UA_DataType *type, Ctx *ctx) { (void)dst, (void)type, (void)ctx; @@ -10458,19 +8742,18 @@ decodeBinaryNotImplemented(void *dst, const UA_DataType *type, Ctx *ctx) { static status decodeBinaryStructure(void *dst, const UA_DataType *type, Ctx *ctx) { /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; uintptr_t ptr = (uintptr_t)dst; status ret = UA_STATUSCODE_GOOD; u8 membersSize = type->membersSize; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; /* Loop over members */ for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) { const UA_DataTypeMember *m = &type->members[i]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptr += m->padding; /* Array */ @@ -10494,23 +8777,18 @@ decodeBinaryStructure(void *dst, const UA_DataType *type, Ctx *ctx) { static status decodeBinaryStructureWithOptFields(void *dst, const UA_DataType *type, Ctx *ctx) { /* Check the recursion limit */ - if(ctx == NULL || ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR); ctx->depth++; uintptr_t ptr = (uintptr_t)dst; UA_UInt32 encodingMask = 0; status ret = UInt32_decodeBinary(&encodingMask, &UA_TYPES[UA_TYPES_UINT32], ctx); - if(ret != UA_STATUSCODE_GOOD) { - ctx->depth--; - return ret; - } + UA_CHECK_STATUS(ret, ctx->depth--; return ret); /* Loop over members */ - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; for(size_t i = 0, o = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) { const UA_DataTypeMember *m = &type->members[i]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + const UA_DataType *mt = m->memberType; ptr += m->padding; if(m->isOptional) { if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) { @@ -10525,8 +8803,7 @@ decodeBinaryStructureWithOptFields(void *dst, const UA_DataType *type, Ctx *ctx) } else { /* Optional Scalar */ *(void *UA_RESTRICT *UA_RESTRICT) ptr = UA_calloc(1, mt->memSize); - if(!*(void *UA_RESTRICT *UA_RESTRICT) ptr) - return UA_STATUSCODE_BADOUTOFMEMORY; + UA_CHECK_MEM(*(void *UA_RESTRICT *UA_RESTRICT) ptr, return UA_STATUSCODE_BADOUTOFMEMORY); ret = decodeBinaryJumpTable[mt->typeKind](*(void *UA_RESTRICT *UA_RESTRICT) ptr, mt, ctx); } ptr += sizeof(void *); @@ -10553,26 +8830,36 @@ decodeBinaryStructureWithOptFields(void *dst, const UA_DataType *type, Ctx *ctx) static status decodeBinaryUnion(void *UA_RESTRICT dst, const UA_DataType *type, Ctx *ctx) { /* Check the recursion limit */ - if(ctx->depth > UA_ENCODING_MAX_RECURSION) - return UA_STATUSCODE_BADENCODINGERROR; + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); + /* Decode the selection directly into the switchfield */ status ret = DECODE_DIRECT(dst, UInt32); - if(ret != UA_STATUSCODE_GOOD) - return ret; + UA_CHECK_STATUS(ret, return ret); + /* No content? */ UA_UInt32 selection = *(UA_UInt32*)dst; if(selection == 0) return UA_STATUSCODE_GOOD; - if(selection-1 >= type->membersSize) - return UA_STATUSCODE_BADDECODINGERROR; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; + /* Sanity check the selection */ + UA_CHECK(selection-1 < type->membersSize, + return UA_STATUSCODE_BADDECODINGERROR); + + /* Select the member */ const UA_DataTypeMember *m = &type->members[selection-1]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; - uintptr_t ptr = ((uintptr_t)dst) + UA_TYPES[UA_TYPES_UINT32].memSize + m->padding; + const UA_DataType *mt = m->memberType; + /* Decode */ ctx->depth++; - ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx); + uintptr_t ptr = ((uintptr_t)dst) + m->padding; /* includes the switchfield */ + if(!m->isArray) { + ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx); + } else { + size_t *length = (size_t *)ptr; + ptr += sizeof(size_t); + ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt, ctx); + } ctx->depth--; return ret; } @@ -10612,8 +8899,9 @@ const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS] = { }; status -UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, - const UA_DataType *type, const UA_DataTypeArray *customTypes) { +UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset, + void *dst, const UA_DataType *type, + const UA_DataTypeArray *customTypes) { /* Set up the context */ Ctx ctx; ctx.pos = &src->data[*offset]; @@ -10625,7 +8913,7 @@ UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, memset(dst, 0, type->memSize); /* Initialize the value */ status ret = decodeBinaryJumpTable[type->typeKind](dst, type, &ctx); - if(ret == UA_STATUSCODE_GOOD) { + if(UA_LIKELY(ret == UA_STATUSCODE_GOOD)) { /* Set the new offset */ *offset = (size_t)(ctx.pos - src->data) / sizeof(u8); } else { @@ -10636,6 +8924,15 @@ UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, return ret; } +UA_StatusCode +UA_decodeBinary(const UA_ByteString *inBuf, + void *p, const UA_DataType *type, + const UA_DecodeBinaryOptions *options) { + size_t offset = 0; + const UA_DataTypeArray *customTypes = options ? options->customTypes : NULL; + return UA_decodeBinaryInternal(inBuf, &offset, p, type, customTypes); +} + /** * Compute the Message Size * ------------------------ @@ -10739,7 +9036,7 @@ CALCSIZE_BINARY(ExtensionObject) { if(src->content.decoded.type->typeId.identifierType != UA_NODEIDTYPE_NUMERIC) return 0; - s += NodeId_calcSizeBinary(&src->content.decoded.type->typeId, NULL); /* Type encoding length */ + s += NodeId_calcSizeBinary(&src->content.decoded.type->binaryEncodingId, NULL); /* Type encoding length */ s += 4; /* Encoding length field */ const UA_DataType *type = src->content.decoded.type; s += calcSizeBinaryJumpTable[type->typeKind](src->content.decoded.data, type); /* Encoding length */ @@ -10763,7 +9060,7 @@ CALCSIZE_BINARY(Variant) { /* The type is wrapped inside an extensionobject */ /* (NodeId + encoding byte + extension object length) * array length */ size_t length = isArray ? src->arrayLength : 1; - s += (NodeId_calcSizeBinary(&src->type->typeId, NULL) + 1 + 4) * length; + s += (NodeId_calcSizeBinary(&src->type->binaryEncodingId, NULL) + 1 + 4) * length; } const UA_Boolean hasDimensions = isArray && src->arrayDimensionsSize > 0; @@ -10814,12 +9111,11 @@ calcSizeBinaryStructure(const void *p, const UA_DataType *type) { size_t s = 0; uintptr_t ptr = (uintptr_t)p; u8 membersSize = type->membersSize; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; /* Loop over members */ for(size_t i = 0; i < membersSize; ++i) { const UA_DataTypeMember *member = &type->members[i]; - const UA_DataType *membertype = &typelists[!member->namespaceZero][member->memberTypeIndex]; + const UA_DataType *membertype = member->memberType; ptr += member->padding; /* Array */ @@ -10846,10 +9142,9 @@ calcSizeBinaryStructureWithOptFields(const void *p, const UA_DataType *type) { /* Loop over members */ uintptr_t ptr = (uintptr_t)p; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; for(size_t i = 0; i < type->membersSize; ++i) { const UA_DataTypeMember *member = &type->members[i]; - const UA_DataType *membertype = &typelists[!member->namespaceZero][member->memberTypeIndex]; + const UA_DataType *membertype = member->memberType; ptr += member->padding; if(member->isOptional) { if((member->isArray && ((*(void* const*)(ptr+sizeof(size_t))) == NULL)) || @@ -10879,18 +9174,22 @@ calcSizeBinaryStructureWithOptFields(const void *p, const UA_DataType *type) { static size_t calcSizeBinaryUnion(const void *p, const UA_DataType *type) { - size_t s = 0; - uintptr_t ptr = (uintptr_t)p; - UA_UInt32 selection = *(UA_UInt32 *) ptr; + size_t s = 4; /* UA_TYPES[UA_TYPES_UINT32].memSize; */ + const UA_UInt32 selection = *(const UA_UInt32 *)p; if(selection == 0) - return UA_TYPES[UA_TYPES_UINT32].memSize; - const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; + return s; + const UA_DataTypeMember *m = &type->members[selection-1]; - const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; - s += UA_TYPES[UA_TYPES_UINT32].memSize; - ptr += UA_TYPES[UA_TYPES_UINT32].memSize; - ptr += m->padding; - s += UA_calcSizeBinary((const void *) ptr, mt); + const UA_DataType *mt = m->memberType; + + uintptr_t ptr = ((uintptr_t)p) + m->padding; /* includes switchfield length */ + if(!m->isArray) { + s += UA_calcSizeBinary((const void*)ptr, mt); + } else { + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + s += Array_calcSizeBinary(*(void *UA_RESTRICT const *)ptr, length, mt); + } return s; } @@ -10939,10 +9238,818 @@ UA_calcSizeBinary(const void *p, const UA_DataType *type) { return calcSizeBinaryJumpTable[type->typeKind](p, type); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/types_generated.c" ***********************************/ +/**** amalgamated original file "/src/ua_types_print.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + + + +/* Printing of NodeIds is always enabled. We need it for logging. */ + +UA_StatusCode +UA_NodeId_print(const UA_NodeId *id, UA_String *output) { + UA_String_clear(output); + if(!id) + return UA_STATUSCODE_GOOD; + + char *nsStr = NULL; + long snprintfLen = 0; + size_t nsLen = 0; + if(id->namespaceIndex != 0) { + nsStr = (char*)UA_malloc(9+1); // strlen("ns=XXXXX;") = 9 + Nullbyte + if(!nsStr) + return UA_STATUSCODE_BADOUTOFMEMORY; + snprintfLen = UA_snprintf(nsStr, 10, "ns=%d;", id->namespaceIndex); + if(snprintfLen < 0 || snprintfLen >= 10) { + UA_free(nsStr); + return UA_STATUSCODE_BADINTERNALERROR; + } + nsLen = (size_t)(snprintfLen); + } + + UA_ByteString byteStr = UA_BYTESTRING_NULL; + switch (id->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 + * chars, delim = 1 , nullbyte = 1-> 17 chars */ + output->length = nsLen + 2 + 10 + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, "%si=%lu", + nsLen > 0 ? nsStr : "", + (unsigned long )id->identifier.numeric); + break; + case UA_NODEIDTYPE_STRING: + /* ns (16bit) = 5 chars, strlen + nullbyte */ + output->length = nsLen + 2 + id->identifier.string.length + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, "%ss=%.*s", + nsLen > 0 ? nsStr : "", (int)id->identifier.string.length, + id->identifier.string.data); + break; + case UA_NODEIDTYPE_GUID: + /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */ + output->length = nsLen + 2 + 36 + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, + "%sg=" UA_PRINTF_GUID_FORMAT, nsLen > 0 ? nsStr : "", + UA_PRINTF_GUID_DATA(id->identifier.guid)); + break; + case UA_NODEIDTYPE_BYTESTRING: + UA_ByteString_toBase64(&id->identifier.byteString, &byteStr); + /* ns (16bit) = 5 chars + LEN + nullbyte */ + output->length = nsLen + 2 + byteStr.length + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_String_clear(&byteStr); + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, "%sb=%.*s", + nsLen > 0 ? nsStr : "", + (int)byteStr.length, byteStr.data); + UA_String_clear(&byteStr); + break; + } + UA_free(nsStr); + + if(snprintfLen < 0 || snprintfLen >= (long) output->length) { + UA_free(output->data); + output->data = NULL; + output->length = 0; + return UA_STATUSCODE_BADINTERNALERROR; + } + output->length = (size_t)snprintfLen; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_ExpandedNodeId_print(const UA_ExpandedNodeId *id, UA_String *output) { + /* Don't print the namespace-index if a NamespaceUri is set */ + UA_NodeId nid = id->nodeId; + if(id->namespaceUri.data != NULL) + nid.namespaceIndex = 0; + + /* Encode the NodeId */ + UA_String outNid = UA_STRING_NULL; + UA_StatusCode res = UA_NodeId_print(&nid, &outNid); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Encode the ServerIndex */ + char svr[100]; + if(id->serverIndex == 0) + svr[0] = 0; + else + UA_snprintf(svr, 100, "svr=%"PRIu32";", id->serverIndex); + size_t svrlen = strlen(svr); + + /* Encode the NamespaceUri */ + char nsu[100]; + if(id->namespaceUri.data == NULL) + nsu[0] = 0; + else + UA_snprintf(nsu, 100, "nsu=%.*s;", (int)id->namespaceUri.length, id->namespaceUri.data); + size_t nsulen = strlen(nsu); + + /* Combine everything */ + res = UA_ByteString_allocBuffer((UA_String*)output, outNid.length + svrlen + nsulen); + if(res == UA_STATUSCODE_GOOD) { + memcpy(output->data, svr, svrlen); + memcpy(&output->data[svrlen], nsu, nsulen); + memcpy(&output->data[svrlen+nsulen], outNid.data, outNid.length); + } + + UA_String_clear(&outNid); + return res; +} + +#ifdef UA_ENABLE_TYPEDESCRIPTION + +/***********************/ +/* Jumptable Signature */ +/***********************/ + +typedef struct UA_PrintElement { + TAILQ_ENTRY(UA_PrintElement) next; + size_t length; + UA_Byte data[]; +} UA_PrintOutput; + +typedef struct { + size_t depth; + TAILQ_HEAD(, UA_PrintElement) outputs; +} UA_PrintContext; + +typedef UA_StatusCode +(*UA_printSignature)(UA_PrintContext *ctx, const void *p, + const UA_DataType *type); + +extern const UA_printSignature printJumpTable[UA_DATATYPEKINDS]; + +/********************/ +/* Helper Functions */ +/********************/ + +static UA_PrintOutput * +UA_PrintContext_addOutput(UA_PrintContext *ctx, size_t length) { + /* Protect against overlong output in pretty-printing */ + if(length > 2<<16) + return NULL; + UA_PrintOutput *output = (UA_PrintOutput*)UA_malloc(sizeof(UA_PrintOutput) + length + 1); + if(!output) + return NULL; + output->length = length; + TAILQ_INSERT_TAIL(&ctx->outputs, output, next); + return output; +} + +static UA_StatusCode +UA_PrintContext_addNewlineTabs(UA_PrintContext *ctx, size_t tabs) { + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, tabs+1); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + out->data[0] = '\n'; + for(size_t i = 1; i <= tabs; i++) + out->data[i] = '\t'; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_PrintContext_addName(UA_PrintContext *ctx, const char *name) { + size_t nameLen = strlen(name); + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, nameLen+2); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(&out->data, name, nameLen); + out->data[nameLen] = ':'; + out->data[nameLen+1] = ' '; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_PrintContext_addString(UA_PrintContext *ctx, const char *str) { + size_t len = strlen(str); + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, len); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(&out->data, str, len); + return UA_STATUSCODE_GOOD; +} + +/*********************/ +/* Printing Routines */ +/*********************/ + +static UA_StatusCode +printArray(UA_PrintContext *ctx, const void *p, const size_t length, + const UA_DataType *type); + +static UA_StatusCode +printBoolean(UA_PrintContext *ctx, const UA_Boolean *p, const UA_DataType *_) { + if(*p) + return UA_PrintContext_addString(ctx, "true"); + return UA_PrintContext_addString(ctx, "false"); +} + +static UA_StatusCode +printSByte(UA_PrintContext *ctx, const UA_SByte *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIi8, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printByte(UA_PrintContext *ctx, const UA_Byte *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIu8, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printInt16(UA_PrintContext *ctx, const UA_Int16 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIi16, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printUInt16(UA_PrintContext *ctx, const UA_UInt16 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIu16, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printInt32(UA_PrintContext *ctx, const UA_Int32 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIi32, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printUInt32(UA_PrintContext *ctx, const UA_UInt32 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIu32, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printInt64(UA_PrintContext *ctx, const UA_Int64 *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 64, "%"PRIi64, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printUInt64(UA_PrintContext *ctx, const UA_UInt64 *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 64, "%"PRIu64, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printFloat(UA_PrintContext *ctx, const UA_Float *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 32, "%f", *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printDouble(UA_PrintContext *ctx, const UA_Double *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 64, "%lf", *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printStatusCode(UA_PrintContext *ctx, const UA_StatusCode *p, const UA_DataType *_) { + return UA_PrintContext_addString(ctx, UA_StatusCode_name(*p)); +} + +static UA_StatusCode +printNodeId(UA_PrintContext *ctx, const UA_NodeId *p, const UA_DataType *_) { + UA_String out; + UA_String_init(&out); + UA_StatusCode res = UA_NodeId_print(p, &out); + if(res != UA_STATUSCODE_GOOD) + return res; + UA_PrintOutput *po = UA_PrintContext_addOutput(ctx, out.length); + if(po) + memcpy(po->data, out.data, out.length); + else + res = UA_STATUSCODE_BADOUTOFMEMORY; + UA_String_clear(&out); + return res; +} + +static UA_StatusCode +printExpandedNodeId(UA_PrintContext *ctx, const UA_ExpandedNodeId *p, const UA_DataType *_) { + UA_String out; + UA_String_init(&out); + UA_StatusCode res = UA_ExpandedNodeId_print(p, &out); + if(res != UA_STATUSCODE_GOOD) + return res; + UA_PrintOutput *po = UA_PrintContext_addOutput(ctx, out.length); + if(!po) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(po->data, out.data, out.length); + UA_String_clear(&out); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +printDateTime(UA_PrintContext *ctx, const UA_DateTime *p, const UA_DataType *_) { + UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset(); + UA_DateTimeStruct dts = UA_DateTime_toStruct(*p); + char dateString[100]; + UA_snprintf((char*)dateString, 100, + "%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)", + dts.year, dts.month, dts.day, dts.hour, dts.min, + dts.sec, dts.milliSec, + (int)(tOffset / UA_DATETIME_SEC / 36)); + return UA_PrintContext_addString(ctx, dateString); +} + +static UA_StatusCode +printGuid(UA_PrintContext *ctx, const UA_Guid *p, const UA_DataType *_) { + char tmp[100]; + UA_snprintf(tmp, 100, UA_PRINTF_GUID_FORMAT, UA_PRINTF_GUID_DATA(*p)); + return UA_PrintContext_addString(ctx, tmp); +} + +static UA_StatusCode +printString(UA_PrintContext *ctx, const UA_String *p, const UA_DataType *_) { + if(!p->data) + return UA_PrintContext_addString(ctx, "NullString"); + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, p->length+2); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_snprintf((char*)out->data, p->length+3, "\"%.*s\"", (int)p->length, p->data); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +printByteString(UA_PrintContext *ctx, const UA_ByteString *p, const UA_DataType *_) { + if(!p->data) + return UA_PrintContext_addString(ctx, "NullByteString"); + UA_String str = UA_BYTESTRING_NULL; + UA_StatusCode res = UA_ByteString_toBase64(p, &str); + if(res != UA_STATUSCODE_GOOD) + return res; + res = printString(ctx, &str, NULL); + UA_String_clear(&str); + return res; +} + +static UA_StatusCode +printQualifiedName(UA_PrintContext *ctx, const UA_QualifiedName *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "NamespaceIndex"); + retval |= printUInt16(ctx, &p->namespaceIndex, NULL); + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Name"); + retval |= printString(ctx, &p->name, NULL); + ctx->depth--; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printLocalizedText(UA_PrintContext *ctx, const UA_LocalizedText *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Locale"); + retval |= printString(ctx, &p->locale, NULL); + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Text"); + retval |= printString(ctx, &p->text, NULL); + ctx->depth--; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printVariant(UA_PrintContext *ctx, const UA_Variant *p, const UA_DataType *_) { + if(!p->type) + return UA_PrintContext_addString(ctx, "NullVariant"); + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "DataType"); + retval |= UA_PrintContext_addString(ctx, p->type->typeName); + retval |= UA_PrintContext_addString(ctx, ","); + + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Value"); + if(UA_Variant_isScalar(p)) + retval |= printJumpTable[p->type->typeKind](ctx, p->data, p->type); + else + retval |= printArray(ctx, p->data, p->arrayLength, p->type); + + if(p->arrayDimensionsSize > 0) { + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "ArrayDimensions"); + retval |= printArray(ctx, p->arrayDimensions, p->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_UINT32]); + } + + ctx->depth--; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printExtensionObject(UA_PrintContext *ctx, const UA_ExtensionObject*p, + const UA_DataType *_) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + switch(p->encoding) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + return UA_PrintContext_addString(ctx, "ExtensionObject(No Body)"); + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + res |= UA_PrintContext_addString(ctx, "ExtensionObject(Binary Encoded) {"); + ctx->depth++; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "DataType"); + res |= printNodeId(ctx, &p->content.encoded.typeId, NULL); + res |= UA_PrintContext_addString(ctx, ","); + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "Body"); + res |= printByteString(ctx, &p->content.encoded.body, NULL); + ctx->depth--; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "}"); + break; + case UA_EXTENSIONOBJECT_ENCODED_XML: + res |= UA_PrintContext_addString(ctx, "ExtensionObject(XML Encoded) {"); + ctx->depth++; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "DataType"); + res |= printNodeId(ctx, &p->content.encoded.typeId, NULL); + res |= UA_PrintContext_addString(ctx, ","); + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "Body"); + res |= printString(ctx, (const UA_String*)&p->content.encoded.body, NULL); + ctx->depth--; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "}"); + break; + case UA_EXTENSIONOBJECT_DECODED: + case UA_EXTENSIONOBJECT_DECODED_NODELETE: + res |= UA_PrintContext_addString(ctx, "ExtensionObject {"); + ctx->depth++; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "DataType"); + res |= UA_PrintContext_addString(ctx, p->content.decoded.type->typeName); + res |= UA_PrintContext_addString(ctx, ","); + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "Body"); + res |= printJumpTable[p->content.decoded.type->typeKind](ctx, + p->content.decoded.data, + p->content.decoded.type); + ctx->depth--; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "}"); + break; + default: + res = UA_STATUSCODE_BADINTERNALERROR; + break; + } + return res; +} -/* Generated from Opc.Ua.Types.bsd with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_datatypes.py - * on host mintaka by user pdie at 2021-06-21 11:34:37 */ +static UA_StatusCode +printDataValue(UA_PrintContext *ctx, const UA_DataValue *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + UA_Boolean comma = false; + + if(p->hasValue) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Value"); + retval |= printVariant(ctx, &p->value, NULL); + comma = true; + } + + if(p->hasStatus) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Status"); + retval |= printStatusCode(ctx, &p->status, NULL); + comma = true; + } + + if(p->hasSourceTimestamp) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "SourceTimestamp"); + retval |= printDateTime(ctx, &p->sourceTimestamp, NULL); + comma = true; + } + + if(p->hasSourcePicoseconds) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "SourcePicoseconds"); + retval |= printUInt16(ctx, &p->sourcePicoseconds, NULL); + comma = true; + } + + if(p->hasServerTimestamp) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "ServerTimestamp"); + retval |= printDateTime(ctx, &p->serverTimestamp, NULL); + comma = true; + } + + if(p->hasServerPicoseconds) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "ServerPicoseconds"); + retval |= printUInt16(ctx, &p->serverPicoseconds, NULL); + comma = true; + } + + ctx->depth--; + if(comma) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + } else { + retval |= UA_PrintContext_addString(ctx, " }"); + } + return retval; +} + +static UA_StatusCode +printDiagnosticInfo(UA_PrintContext *ctx, const UA_DiagnosticInfo *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + UA_Boolean comma = false; + + if(p->hasSymbolicId) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "SymbolicId"); + retval |= printInt32(ctx, &p->symbolicId, NULL); + comma = true; + } + + if(p->hasNamespaceUri) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "NamespaceUri"); + retval |= printInt32(ctx, &p->namespaceUri, NULL); + comma = true; + } + + if(p->hasLocalizedText) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "LocalizedText"); + retval |= printInt32(ctx, &p->localizedText, NULL); + comma = true; + } + + if(p->hasLocale) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Locale"); + retval |= printInt32(ctx, &p->locale, NULL); + comma = true; + } + + if(p->hasAdditionalInfo) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "AdditionalInfo"); + retval |= printString(ctx, &p->additionalInfo, NULL); + comma = true; + } + + if(p->hasInnerStatusCode) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "InnerStatusCode"); + retval |= printStatusCode(ctx, &p->innerStatusCode, NULL); + comma = true; + } + + if(p->hasInnerDiagnosticInfo) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "InnerDiagnosticInfo"); + retval |= printDiagnosticInfo(ctx, p->innerDiagnosticInfo, NULL); + comma = true; + } + + ctx->depth--; + if(comma) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + } else { + retval |= UA_PrintContext_addString(ctx, " }"); + } + return retval; +} + +static UA_StatusCode +printArray(UA_PrintContext *ctx, const void *p, const size_t length, + const UA_DataType *type) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(!p) { + retval |= UA_PrintContext_addString(ctx, "Array(-1, "); + retval |= UA_PrintContext_addString(ctx, type->typeName); + retval |= UA_PrintContext_addString(ctx, ")"); + return retval; + } + + UA_UInt32 length32 = (UA_UInt32)length; + retval |= UA_PrintContext_addString(ctx, "Array("); + retval |= printUInt32(ctx, &length32, NULL); + retval |= UA_PrintContext_addString(ctx, ", "); + retval |= UA_PrintContext_addString(ctx, type->typeName); + retval |= UA_PrintContext_addString(ctx, ") {"); + ctx->depth++; + uintptr_t target = (uintptr_t)p; + for(UA_UInt32 i = 0; i < length; i++) { + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + printUInt32(ctx, &i, NULL); + retval |= UA_PrintContext_addString(ctx, ": "); + printJumpTable[type->typeKind](ctx, (const void*)target, type); + if(i < length - 1) + retval |= UA_PrintContext_addString(ctx, ","); + target += type->memSize; + } + ctx->depth--; + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printStructure(UA_PrintContext *ctx, const void *p, const UA_DataType *type) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + uintptr_t ptrs = (uintptr_t)p; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + for(size_t i = 0; i < type->membersSize; ++i) { + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptrs += m->padding; + retval |= UA_PrintContext_addName(ctx, m->memberName); + if(!m->isArray) { + retval |= printJumpTable[mt->typeKind](ctx, (const void *)ptrs, mt); + ptrs += mt->memSize; + } else { + const size_t size = *((const size_t*)ptrs); + ptrs += sizeof(size_t); + retval |= printArray(ctx, *(void* const*)ptrs, size, mt); + ptrs += sizeof(void*); + } + if(i < (size_t)(type->membersSize - 1)) + retval |= UA_PrintContext_addString(ctx, ","); + } + ctx->depth--; + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printNotImplemented(UA_PrintContext *ctx, const void *p, const UA_DataType *type) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + res |= UA_PrintContext_addString(ctx, type->typeName); + res |= UA_PrintContext_addString(ctx, " (Printing Not Implemented)"); + return res; +} + +const UA_printSignature printJumpTable[UA_DATATYPEKINDS] = { + (UA_printSignature)printBoolean, + (UA_printSignature)printSByte, + (UA_printSignature)printByte, + (UA_printSignature)printInt16, + (UA_printSignature)printUInt16, + (UA_printSignature)printInt32, + (UA_printSignature)printUInt32, + (UA_printSignature)printInt64, + (UA_printSignature)printUInt64, + (UA_printSignature)printFloat, + (UA_printSignature)printDouble, + (UA_printSignature)printString, + (UA_printSignature)printDateTime, + (UA_printSignature)printGuid, + (UA_printSignature)printByteString, + (UA_printSignature)printString, /* XmlElement */ + (UA_printSignature)printNodeId, + (UA_printSignature)printExpandedNodeId, + (UA_printSignature)printStatusCode, + (UA_printSignature)printQualifiedName, + (UA_printSignature)printLocalizedText, + (UA_printSignature)printExtensionObject, + (UA_printSignature)printDataValue, + (UA_printSignature)printVariant, + (UA_printSignature)printDiagnosticInfo, + (UA_printSignature)printNotImplemented, /* Decimal */ + (UA_printSignature)printUInt32, /* Enumeration */ + (UA_printSignature)printStructure, + (UA_printSignature)printNotImplemented, /* Structure with Optional Fields */ + (UA_printSignature)printNotImplemented, /* Union */ + (UA_printSignature)printNotImplemented /* BitfieldCluster*/ +}; + +UA_StatusCode +UA_print(const void *p, const UA_DataType *type, UA_String *output) { + UA_PrintContext ctx; + ctx.depth = 0; + TAILQ_INIT(&ctx.outputs); + + /* Encode */ + UA_StatusCode retval = printJumpTable[type->typeKind](&ctx, p, type); + + /* Allocate memory for the output */ + if(retval == UA_STATUSCODE_GOOD) { + size_t total = 0; + UA_PrintOutput *out; + TAILQ_FOREACH(out, &ctx.outputs, next) + total += out->length; + retval = UA_ByteString_allocBuffer((UA_String*)output, total); + } + + /* Write the output */ + if(retval == UA_STATUSCODE_GOOD) { + size_t pos = 0; + UA_PrintOutput *out; + TAILQ_FOREACH(out, &ctx.outputs, next) { + memcpy(&output->data[pos], out->data, out->length); + pos += out->length; + } + } + + /* Free the context */ + UA_PrintOutput *o, *o2; + TAILQ_FOREACH_SAFE(o, &ctx.outputs, next, o2) { + TAILQ_REMOVE(&ctx.outputs, o, next); + UA_free(o); + } + return retval; +} + +#endif /* UA_ENABLE_TYPEDESCRIPTION */ + +/**** amalgamated original file "/build/src_generated/open62541/types_generated.c" ****/ + +/********************************** + * Autogenerated -- do not modify * + **********************************/ /* Boolean */ @@ -11020,6 +10127,23 @@ UA_calcSizeBinary(const void *p, const UA_DataType *type) { /* DiagnosticInfo */ #define DiagnosticInfo_members NULL +/* KeyValuePair */ +static UA_DataTypeMember KeyValuePair_members[2] = { +{ + UA_TYPENAME("Key") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_KeyValuePair, value) - offsetof(UA_KeyValuePair, key) - sizeof(UA_QualifiedName), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + /* NodeClass */ #define NodeClass_members NULL @@ -11030,199 +10154,176 @@ UA_calcSizeBinary(const void *p, const UA_DataType *type) { static UA_DataTypeMember StructureField_members[7] = { { UA_TYPENAME("Name") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_StructureField, description) - offsetof(UA_StructureField, name) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DataType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_StructureField, dataType) - offsetof(UA_StructureField, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ValueRank") /* .memberName */ - UA_TYPES_INT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ offsetof(UA_StructureField, valueRank) - offsetof(UA_StructureField, dataType) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ArrayDimensions") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_StructureField, arrayDimensionsSize) - offsetof(UA_StructureField, valueRank) - sizeof(UA_Int32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxStringLength") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_StructureField, maxStringLength) - offsetof(UA_StructureField, arrayDimensions) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsOptional") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_StructureField, isOptional) - offsetof(UA_StructureField, maxStringLength) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* StructureDefinition */ static UA_DataTypeMember StructureDefinition_members[4] = { { UA_TYPENAME("DefaultEncodingId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BaseDataType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_StructureDefinition, baseDataType) - offsetof(UA_StructureDefinition, defaultEncodingId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("StructureType") /* .memberName */ - UA_TYPES_STRUCTURETYPE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRUCTURETYPE], /* .memberType */ offsetof(UA_StructureDefinition, structureType) - offsetof(UA_StructureDefinition, baseDataType) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Fields") /* .memberName */ - UA_TYPES_STRUCTUREFIELD, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRUCTUREFIELD], /* .memberType */ offsetof(UA_StructureDefinition, fieldsSize) - offsetof(UA_StructureDefinition, structureType) - sizeof(UA_StructureType), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* Argument */ static UA_DataTypeMember Argument_members[5] = { { UA_TYPENAME("Name") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DataType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_Argument, dataType) - offsetof(UA_Argument, name) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ValueRank") /* .memberName */ - UA_TYPES_INT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ offsetof(UA_Argument, valueRank) - offsetof(UA_Argument, dataType) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ArrayDimensions") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_Argument, arrayDimensionsSize) - offsetof(UA_Argument, valueRank) - sizeof(UA_Int32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_Argument, description) - offsetof(UA_Argument, arrayDimensions) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EnumValueType */ static UA_DataTypeMember EnumValueType_members[3] = { { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_INT64, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT64], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_EnumValueType, displayName) - offsetof(UA_EnumValueType, value) - sizeof(UA_Int64), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_EnumValueType, description) - offsetof(UA_EnumValueType, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EnumField */ static UA_DataTypeMember EnumField_members[4] = { { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_INT64, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT64], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_EnumField, displayName) - offsetof(UA_EnumField, value) - sizeof(UA_Int64), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_EnumField, description) - offsetof(UA_EnumField, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Name") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_EnumField, name) - offsetof(UA_EnumField, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* Duration */ @@ -11238,19 +10339,17 @@ static UA_DataTypeMember EnumField_members[4] = { static UA_DataTypeMember TimeZoneDataType_members[2] = { { UA_TYPENAME("Offset") /* .memberName */ - UA_TYPES_INT16, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT16], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DaylightSavingInOffset") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_TimeZoneDataType, daylightSavingInOffset) - offsetof(UA_TimeZoneDataType, offset) - sizeof(UA_Int16), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ApplicationType */ @@ -11260,234 +10359,207 @@ static UA_DataTypeMember TimeZoneDataType_members[2] = { static UA_DataTypeMember ApplicationDescription_members[7] = { { UA_TYPENAME("ApplicationUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ProductUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ApplicationDescription, productUri) - offsetof(UA_ApplicationDescription, applicationUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ApplicationName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ApplicationDescription, applicationName) - offsetof(UA_ApplicationDescription, productUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ApplicationType") /* .memberName */ - UA_TYPES_APPLICATIONTYPE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_APPLICATIONTYPE], /* .memberType */ offsetof(UA_ApplicationDescription, applicationType) - offsetof(UA_ApplicationDescription, applicationName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("GatewayServerUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ApplicationDescription, gatewayServerUri) - offsetof(UA_ApplicationDescription, applicationType) - sizeof(UA_ApplicationType), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiscoveryProfileUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ApplicationDescription, discoveryProfileUri) - offsetof(UA_ApplicationDescription, gatewayServerUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiscoveryUrls") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ApplicationDescription, discoveryUrlsSize) - offsetof(UA_ApplicationDescription, discoveryProfileUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RequestHeader */ static UA_DataTypeMember RequestHeader_members[7] = { { UA_TYPENAME("AuthenticationToken") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Timestamp") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_RequestHeader, timestamp) - offsetof(UA_RequestHeader, authenticationToken) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestHandle") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_RequestHeader, requestHandle) - offsetof(UA_RequestHeader, timestamp) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReturnDiagnostics") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_RequestHeader, returnDiagnostics) - offsetof(UA_RequestHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AuditEntryId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_RequestHeader, auditEntryId) - offsetof(UA_RequestHeader, returnDiagnostics) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TimeoutHint") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_RequestHeader, timeoutHint) - offsetof(UA_RequestHeader, auditEntryId) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AdditionalHeader") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_RequestHeader, additionalHeader) - offsetof(UA_RequestHeader, timeoutHint) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ResponseHeader */ static UA_DataTypeMember ResponseHeader_members[6] = { { UA_TYPENAME("Timestamp") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestHandle") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ResponseHeader, requestHandle) - offsetof(UA_ResponseHeader, timestamp) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServiceResult") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_ResponseHeader, serviceResult) - offsetof(UA_ResponseHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServiceDiagnostics") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_ResponseHeader, serviceDiagnostics) - offsetof(UA_ResponseHeader, serviceResult) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("StringTable") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ResponseHeader, stringTableSize) - offsetof(UA_ResponseHeader, serviceDiagnostics) - sizeof(UA_DiagnosticInfo), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AdditionalHeader") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_ResponseHeader, additionalHeader) - offsetof(UA_ResponseHeader, stringTable) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ServiceFault */ static UA_DataTypeMember ServiceFault_members[1] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* FindServersRequest */ static UA_DataTypeMember FindServersRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndpointUrl") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_FindServersRequest, endpointUrl) - offsetof(UA_FindServersRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("LocaleIds") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_FindServersRequest, localeIdsSize) - offsetof(UA_FindServersRequest, endpointUrl) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerUris") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_FindServersRequest, serverUrisSize) - offsetof(UA_FindServersRequest, localeIds) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* FindServersResponse */ static UA_DataTypeMember FindServersResponse_members[2] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Servers") /* .memberName */ - UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */ offsetof(UA_FindServersResponse, serversSize) - offsetof(UA_FindServersResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MessageSecurityMode */ @@ -11500,164 +10572,145 @@ static UA_DataTypeMember FindServersResponse_members[2] = { static UA_DataTypeMember UserTokenPolicy_members[5] = { { UA_TYPENAME("PolicyId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TokenType") /* .memberName */ - UA_TYPES_USERTOKENTYPE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_USERTOKENTYPE], /* .memberType */ offsetof(UA_UserTokenPolicy, tokenType) - offsetof(UA_UserTokenPolicy, policyId) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IssuedTokenType") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_UserTokenPolicy, issuedTokenType) - offsetof(UA_UserTokenPolicy, tokenType) - sizeof(UA_UserTokenType), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IssuerEndpointUrl") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - offsetof(UA_UserTokenPolicy, issuedTokenType) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityPolicyUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_UserTokenPolicy, securityPolicyUri) - offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EndpointDescription */ static UA_DataTypeMember EndpointDescription_members[8] = { { UA_TYPENAME("EndpointUrl") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Server") /* .memberName */ - UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */ offsetof(UA_EndpointDescription, server) - offsetof(UA_EndpointDescription, endpointUrl) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerCertificate") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_EndpointDescription, serverCertificate) - offsetof(UA_EndpointDescription, server) - sizeof(UA_ApplicationDescription), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityMode") /* .memberName */ - UA_TYPES_MESSAGESECURITYMODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */ offsetof(UA_EndpointDescription, securityMode) - offsetof(UA_EndpointDescription, serverCertificate) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityPolicyUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_EndpointDescription, securityPolicyUri) - offsetof(UA_EndpointDescription, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserIdentityTokens") /* .memberName */ - UA_TYPES_USERTOKENPOLICY, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_USERTOKENPOLICY], /* .memberType */ offsetof(UA_EndpointDescription, userIdentityTokensSize) - offsetof(UA_EndpointDescription, securityPolicyUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TransportProfileUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_EndpointDescription, transportProfileUri) - offsetof(UA_EndpointDescription, userIdentityTokens) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityLevel") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_EndpointDescription, securityLevel) - offsetof(UA_EndpointDescription, transportProfileUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* GetEndpointsRequest */ static UA_DataTypeMember GetEndpointsRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndpointUrl") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_GetEndpointsRequest, endpointUrl) - offsetof(UA_GetEndpointsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("LocaleIds") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_GetEndpointsRequest, localeIdsSize) - offsetof(UA_GetEndpointsRequest, endpointUrl) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ProfileUris") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_GetEndpointsRequest, profileUrisSize) - offsetof(UA_GetEndpointsRequest, localeIds) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* GetEndpointsResponse */ static UA_DataTypeMember GetEndpointsResponse_members[2] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Endpoints") /* .memberName */ - UA_TYPES_ENDPOINTDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */ offsetof(UA_GetEndpointsResponse, endpointsSize) - offsetof(UA_GetEndpointsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SecurityTokenRequestType */ @@ -11667,558 +10720,495 @@ static UA_DataTypeMember GetEndpointsResponse_members[2] = { static UA_DataTypeMember ChannelSecurityToken_members[4] = { { UA_TYPENAME("ChannelId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TokenId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ChannelSecurityToken, tokenId) - offsetof(UA_ChannelSecurityToken, channelId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CreatedAt") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ChannelSecurityToken, createdAt) - offsetof(UA_ChannelSecurityToken, tokenId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedLifetime") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ChannelSecurityToken, revisedLifetime) - offsetof(UA_ChannelSecurityToken, createdAt) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* OpenSecureChannelRequest */ static UA_DataTypeMember OpenSecureChannelRequest_members[6] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientProtocolVersion") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - offsetof(UA_OpenSecureChannelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestType") /* .memberName */ - UA_TYPES_SECURITYTOKENREQUESTTYPE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE], /* .memberType */ offsetof(UA_OpenSecureChannelRequest, requestType) - offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityMode") /* .memberName */ - UA_TYPES_MESSAGESECURITYMODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */ offsetof(UA_OpenSecureChannelRequest, securityMode) - offsetof(UA_OpenSecureChannelRequest, requestType) - sizeof(UA_SecurityTokenRequestType), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientNonce") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_OpenSecureChannelRequest, clientNonce) - offsetof(UA_OpenSecureChannelRequest, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedLifetime") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_OpenSecureChannelRequest, requestedLifetime) - offsetof(UA_OpenSecureChannelRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* OpenSecureChannelResponse */ static UA_DataTypeMember OpenSecureChannelResponse_members[4] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerProtocolVersion") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - offsetof(UA_OpenSecureChannelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityToken") /* .memberName */ - UA_TYPES_CHANNELSECURITYTOKEN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN], /* .memberType */ offsetof(UA_OpenSecureChannelResponse, securityToken) - offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerNonce") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_OpenSecureChannelResponse, serverNonce) - offsetof(UA_OpenSecureChannelResponse, securityToken) - sizeof(UA_ChannelSecurityToken), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CloseSecureChannelRequest */ static UA_DataTypeMember CloseSecureChannelRequest_members[1] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CloseSecureChannelResponse */ static UA_DataTypeMember CloseSecureChannelResponse_members[1] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SignedSoftwareCertificate */ static UA_DataTypeMember SignedSoftwareCertificate_members[2] = { { UA_TYPENAME("CertificateData") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Signature") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_SignedSoftwareCertificate, signature) - offsetof(UA_SignedSoftwareCertificate, certificateData) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SignatureData */ static UA_DataTypeMember SignatureData_members[2] = { { UA_TYPENAME("Algorithm") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Signature") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_SignatureData, signature) - offsetof(UA_SignatureData, algorithm) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CreateSessionRequest */ static UA_DataTypeMember CreateSessionRequest_members[9] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientDescription") /* .memberName */ - UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */ offsetof(UA_CreateSessionRequest, clientDescription) - offsetof(UA_CreateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_CreateSessionRequest, serverUri) - offsetof(UA_CreateSessionRequest, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndpointUrl") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_CreateSessionRequest, endpointUrl) - offsetof(UA_CreateSessionRequest, serverUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SessionName") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_CreateSessionRequest, sessionName) - offsetof(UA_CreateSessionRequest, endpointUrl) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientNonce") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_CreateSessionRequest, clientNonce) - offsetof(UA_CreateSessionRequest, sessionName) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientCertificate") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_CreateSessionRequest, clientCertificate) - offsetof(UA_CreateSessionRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedSessionTimeout") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - offsetof(UA_CreateSessionRequest, clientCertificate) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxResponseMessageSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSessionRequest, maxResponseMessageSize) - offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CreateSessionResponse */ static UA_DataTypeMember CreateSessionResponse_members[10] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SessionId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_CreateSessionResponse, sessionId) - offsetof(UA_CreateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AuthenticationToken") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_CreateSessionResponse, authenticationToken) - offsetof(UA_CreateSessionResponse, sessionId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedSessionTimeout") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - offsetof(UA_CreateSessionResponse, authenticationToken) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerNonce") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_CreateSessionResponse, serverNonce) - offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerCertificate") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_CreateSessionResponse, serverCertificate) - offsetof(UA_CreateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerEndpoints") /* .memberName */ - UA_TYPES_ENDPOINTDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */ offsetof(UA_CreateSessionResponse, serverEndpointsSize) - offsetof(UA_CreateSessionResponse, serverCertificate) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerSoftwareCertificates") /* .memberName */ - UA_TYPES_SIGNEDSOFTWARECERTIFICATE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */ offsetof(UA_CreateSessionResponse, serverSoftwareCertificatesSize) - offsetof(UA_CreateSessionResponse, serverEndpoints) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerSignature") /* .memberName */ - UA_TYPES_SIGNATUREDATA, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */ offsetof(UA_CreateSessionResponse, serverSignature) - offsetof(UA_CreateSessionResponse, serverSoftwareCertificates) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxRequestMessageSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSessionResponse, maxRequestMessageSize) - offsetof(UA_CreateSessionResponse, serverSignature) - sizeof(UA_SignatureData), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* UserIdentityToken */ static UA_DataTypeMember UserIdentityToken_members[1] = { { UA_TYPENAME("PolicyId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AnonymousIdentityToken */ static UA_DataTypeMember AnonymousIdentityToken_members[1] = { { UA_TYPENAME("PolicyId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* UserNameIdentityToken */ static UA_DataTypeMember UserNameIdentityToken_members[4] = { { UA_TYPENAME("PolicyId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserName") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_UserNameIdentityToken, userName) - offsetof(UA_UserNameIdentityToken, policyId) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Password") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_UserNameIdentityToken, password) - offsetof(UA_UserNameIdentityToken, userName) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EncryptionAlgorithm") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_UserNameIdentityToken, encryptionAlgorithm) - offsetof(UA_UserNameIdentityToken, password) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* X509IdentityToken */ static UA_DataTypeMember X509IdentityToken_members[2] = { { UA_TYPENAME("PolicyId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CertificateData") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_X509IdentityToken, certificateData) - offsetof(UA_X509IdentityToken, policyId) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* IssuedIdentityToken */ static UA_DataTypeMember IssuedIdentityToken_members[3] = { { UA_TYPENAME("PolicyId") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TokenData") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_IssuedIdentityToken, tokenData) - offsetof(UA_IssuedIdentityToken, policyId) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EncryptionAlgorithm") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_IssuedIdentityToken, encryptionAlgorithm) - offsetof(UA_IssuedIdentityToken, tokenData) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ActivateSessionRequest */ static UA_DataTypeMember ActivateSessionRequest_members[6] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientSignature") /* .memberName */ - UA_TYPES_SIGNATUREDATA, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */ offsetof(UA_ActivateSessionRequest, clientSignature) - offsetof(UA_ActivateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ClientSoftwareCertificates") /* .memberName */ - UA_TYPES_SIGNEDSOFTWARECERTIFICATE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */ offsetof(UA_ActivateSessionRequest, clientSoftwareCertificatesSize) - offsetof(UA_ActivateSessionRequest, clientSignature) - sizeof(UA_SignatureData), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("LocaleIds") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ActivateSessionRequest, localeIdsSize) - offsetof(UA_ActivateSessionRequest, clientSoftwareCertificates) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserIdentityToken") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_ActivateSessionRequest, userIdentityToken) - offsetof(UA_ActivateSessionRequest, localeIds) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserTokenSignature") /* .memberName */ - UA_TYPES_SIGNATUREDATA, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */ offsetof(UA_ActivateSessionRequest, userTokenSignature) - offsetof(UA_ActivateSessionRequest, userIdentityToken) - sizeof(UA_ExtensionObject), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ActivateSessionResponse */ static UA_DataTypeMember ActivateSessionResponse_members[4] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ServerNonce") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_ActivateSessionResponse, serverNonce) - offsetof(UA_ActivateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_ActivateSessionResponse, resultsSize) - offsetof(UA_ActivateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_ActivateSessionResponse, diagnosticInfosSize) - offsetof(UA_ActivateSessionResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CloseSessionRequest */ static UA_DataTypeMember CloseSessionRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DeleteSubscriptions") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_CloseSessionRequest, deleteSubscriptions) - offsetof(UA_CloseSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CloseSessionResponse */ static UA_DataTypeMember CloseSessionResponse_members[1] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* NodeAttributesMask */ @@ -12228,946 +11218,836 @@ static UA_DataTypeMember CloseSessionResponse_members[1] = { static UA_DataTypeMember NodeAttributes_members[5] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_NodeAttributes, displayName) - offsetof(UA_NodeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_NodeAttributes, description) - offsetof(UA_NodeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_NodeAttributes, writeMask) - offsetof(UA_NodeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_NodeAttributes, userWriteMask) - offsetof(UA_NodeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ObjectAttributes */ static UA_DataTypeMember ObjectAttributes_members[6] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ObjectAttributes, displayName) - offsetof(UA_ObjectAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ObjectAttributes, description) - offsetof(UA_ObjectAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ObjectAttributes, writeMask) - offsetof(UA_ObjectAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ObjectAttributes, userWriteMask) - offsetof(UA_ObjectAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EventNotifier") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_ObjectAttributes, eventNotifier) - offsetof(UA_ObjectAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* VariableAttributes */ static UA_DataTypeMember VariableAttributes_members[13] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_VariableAttributes, displayName) - offsetof(UA_VariableAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_VariableAttributes, description) - offsetof(UA_VariableAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_VariableAttributes, writeMask) - offsetof(UA_VariableAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_VariableAttributes, userWriteMask) - offsetof(UA_VariableAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ offsetof(UA_VariableAttributes, value) - offsetof(UA_VariableAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DataType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_VariableAttributes, dataType) - offsetof(UA_VariableAttributes, value) - sizeof(UA_Variant), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ValueRank") /* .memberName */ - UA_TYPES_INT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ offsetof(UA_VariableAttributes, valueRank) - offsetof(UA_VariableAttributes, dataType) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ArrayDimensions") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_VariableAttributes, arrayDimensionsSize) - offsetof(UA_VariableAttributes, valueRank) - sizeof(UA_Int32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AccessLevel") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_VariableAttributes, accessLevel) - offsetof(UA_VariableAttributes, arrayDimensions) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserAccessLevel") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_VariableAttributes, userAccessLevel) - offsetof(UA_VariableAttributes, accessLevel) - sizeof(UA_Byte), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MinimumSamplingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_VariableAttributes, minimumSamplingInterval) - offsetof(UA_VariableAttributes, userAccessLevel) - sizeof(UA_Byte), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Historizing") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_VariableAttributes, historizing) - offsetof(UA_VariableAttributes, minimumSamplingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MethodAttributes */ static UA_DataTypeMember MethodAttributes_members[7] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_MethodAttributes, displayName) - offsetof(UA_MethodAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_MethodAttributes, description) - offsetof(UA_MethodAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_MethodAttributes, writeMask) - offsetof(UA_MethodAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_MethodAttributes, userWriteMask) - offsetof(UA_MethodAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Executable") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_MethodAttributes, executable) - offsetof(UA_MethodAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserExecutable") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_MethodAttributes, userExecutable) - offsetof(UA_MethodAttributes, executable) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ObjectTypeAttributes */ static UA_DataTypeMember ObjectTypeAttributes_members[6] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ObjectTypeAttributes, displayName) - offsetof(UA_ObjectTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ObjectTypeAttributes, description) - offsetof(UA_ObjectTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ObjectTypeAttributes, writeMask) - offsetof(UA_ObjectTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ObjectTypeAttributes, userWriteMask) - offsetof(UA_ObjectTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsAbstract") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ObjectTypeAttributes, isAbstract) - offsetof(UA_ObjectTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* VariableTypeAttributes */ static UA_DataTypeMember VariableTypeAttributes_members[10] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_VariableTypeAttributes, displayName) - offsetof(UA_VariableTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_VariableTypeAttributes, description) - offsetof(UA_VariableTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_VariableTypeAttributes, writeMask) - offsetof(UA_VariableTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_VariableTypeAttributes, userWriteMask) - offsetof(UA_VariableTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ offsetof(UA_VariableTypeAttributes, value) - offsetof(UA_VariableTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DataType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_VariableTypeAttributes, dataType) - offsetof(UA_VariableTypeAttributes, value) - sizeof(UA_Variant), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ValueRank") /* .memberName */ - UA_TYPES_INT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ offsetof(UA_VariableTypeAttributes, valueRank) - offsetof(UA_VariableTypeAttributes, dataType) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ArrayDimensions") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_VariableTypeAttributes, arrayDimensionsSize) - offsetof(UA_VariableTypeAttributes, valueRank) - sizeof(UA_Int32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsAbstract") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_VariableTypeAttributes, isAbstract) - offsetof(UA_VariableTypeAttributes, arrayDimensions) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReferenceTypeAttributes */ static UA_DataTypeMember ReferenceTypeAttributes_members[8] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, displayName) - offsetof(UA_ReferenceTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, description) - offsetof(UA_ReferenceTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, writeMask) - offsetof(UA_ReferenceTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, userWriteMask) - offsetof(UA_ReferenceTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsAbstract") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, isAbstract) - offsetof(UA_ReferenceTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Symmetric") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, symmetric) - offsetof(UA_ReferenceTypeAttributes, isAbstract) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("InverseName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ReferenceTypeAttributes, inverseName) - offsetof(UA_ReferenceTypeAttributes, symmetric) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DataTypeAttributes */ static UA_DataTypeMember DataTypeAttributes_members[6] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_DataTypeAttributes, displayName) - offsetof(UA_DataTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_DataTypeAttributes, description) - offsetof(UA_DataTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_DataTypeAttributes, writeMask) - offsetof(UA_DataTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_DataTypeAttributes, userWriteMask) - offsetof(UA_DataTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsAbstract") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_DataTypeAttributes, isAbstract) - offsetof(UA_DataTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ViewAttributes */ static UA_DataTypeMember ViewAttributes_members[7] = { { UA_TYPENAME("SpecifiedAttributes") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ViewAttributes, displayName) - offsetof(UA_ViewAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ViewAttributes, description) - offsetof(UA_ViewAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ViewAttributes, writeMask) - offsetof(UA_ViewAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserWriteMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ViewAttributes, userWriteMask) - offsetof(UA_ViewAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ContainsNoLoops") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ViewAttributes, containsNoLoops) - offsetof(UA_ViewAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EventNotifier") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_ViewAttributes, eventNotifier) - offsetof(UA_ViewAttributes, containsNoLoops) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddNodesItem */ static UA_DataTypeMember AddNodesItem_members[7] = { { UA_TYPENAME("ParentNodeId") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReferenceTypeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_AddNodesItem, referenceTypeId) - offsetof(UA_AddNodesItem, parentNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedNewNodeId") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ offsetof(UA_AddNodesItem, requestedNewNodeId) - offsetof(UA_AddNodesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BrowseName") /* .memberName */ - UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ offsetof(UA_AddNodesItem, browseName) - offsetof(UA_AddNodesItem, requestedNewNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodeClass") /* .memberName */ - UA_TYPES_NODECLASS, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */ offsetof(UA_AddNodesItem, nodeClass) - offsetof(UA_AddNodesItem, browseName) - sizeof(UA_QualifiedName), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodeAttributes") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_AddNodesItem, nodeAttributes) - offsetof(UA_AddNodesItem, nodeClass) - sizeof(UA_NodeClass), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TypeDefinition") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ offsetof(UA_AddNodesItem, typeDefinition) - offsetof(UA_AddNodesItem, nodeAttributes) - sizeof(UA_ExtensionObject), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddNodesResult */ static UA_DataTypeMember AddNodesResult_members[2] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AddedNodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_AddNodesResult, addedNodeId) - offsetof(UA_AddNodesResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddNodesRequest */ static UA_DataTypeMember AddNodesRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToAdd") /* .memberName */ - UA_TYPES_ADDNODESITEM, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_ADDNODESITEM], /* .memberType */ offsetof(UA_AddNodesRequest, nodesToAddSize) - offsetof(UA_AddNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddNodesResponse */ static UA_DataTypeMember AddNodesResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_ADDNODESRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_ADDNODESRESULT], /* .memberType */ offsetof(UA_AddNodesResponse, resultsSize) - offsetof(UA_AddNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_AddNodesResponse, diagnosticInfosSize) - offsetof(UA_AddNodesResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddReferencesItem */ static UA_DataTypeMember AddReferencesItem_members[6] = { { UA_TYPENAME("SourceNodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReferenceTypeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_AddReferencesItem, referenceTypeId) - offsetof(UA_AddReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsForward") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_AddReferencesItem, isForward) - offsetof(UA_AddReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TargetServerUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_AddReferencesItem, targetServerUri) - offsetof(UA_AddReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TargetNodeId") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ offsetof(UA_AddReferencesItem, targetNodeId) - offsetof(UA_AddReferencesItem, targetServerUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TargetNodeClass") /* .memberName */ - UA_TYPES_NODECLASS, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */ offsetof(UA_AddReferencesItem, targetNodeClass) - offsetof(UA_AddReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddReferencesRequest */ static UA_DataTypeMember AddReferencesRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReferencesToAdd") /* .memberName */ - UA_TYPES_ADDREFERENCESITEM, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], /* .memberType */ offsetof(UA_AddReferencesRequest, referencesToAddSize) - offsetof(UA_AddReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AddReferencesResponse */ static UA_DataTypeMember AddReferencesResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_AddReferencesResponse, resultsSize) - offsetof(UA_AddReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_AddReferencesResponse, diagnosticInfosSize) - offsetof(UA_AddReferencesResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteNodesItem */ static UA_DataTypeMember DeleteNodesItem_members[2] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DeleteTargetReferences") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_DeleteNodesItem, deleteTargetReferences) - offsetof(UA_DeleteNodesItem, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteNodesRequest */ static UA_DataTypeMember DeleteNodesRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToDelete") /* .memberName */ - UA_TYPES_DELETENODESITEM, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DELETENODESITEM], /* .memberType */ offsetof(UA_DeleteNodesRequest, nodesToDeleteSize) - offsetof(UA_DeleteNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteNodesResponse */ static UA_DataTypeMember DeleteNodesResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_DeleteNodesResponse, resultsSize) - offsetof(UA_DeleteNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_DeleteNodesResponse, diagnosticInfosSize) - offsetof(UA_DeleteNodesResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteReferencesItem */ static UA_DataTypeMember DeleteReferencesItem_members[5] = { { UA_TYPENAME("SourceNodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReferenceTypeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_DeleteReferencesItem, referenceTypeId) - offsetof(UA_DeleteReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsForward") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_DeleteReferencesItem, isForward) - offsetof(UA_DeleteReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TargetNodeId") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ offsetof(UA_DeleteReferencesItem, targetNodeId) - offsetof(UA_DeleteReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DeleteBidirectional") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_DeleteReferencesItem, deleteBidirectional) - offsetof(UA_DeleteReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteReferencesRequest */ static UA_DataTypeMember DeleteReferencesRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReferencesToDelete") /* .memberName */ - UA_TYPES_DELETEREFERENCESITEM, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], /* .memberType */ offsetof(UA_DeleteReferencesRequest, referencesToDeleteSize) - offsetof(UA_DeleteReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteReferencesResponse */ static UA_DataTypeMember DeleteReferencesResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_DeleteReferencesResponse, resultsSize) - offsetof(UA_DeleteReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_DeleteReferencesResponse, diagnosticInfosSize) - offsetof(UA_DeleteReferencesResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseDirection */ @@ -13177,78 +12057,69 @@ static UA_DataTypeMember DeleteReferencesResponse_members[3] = { static UA_DataTypeMember ViewDescription_members[3] = { { UA_TYPENAME("ViewId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Timestamp") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ViewDescription, timestamp) - offsetof(UA_ViewDescription, viewId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ViewVersion") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ViewDescription, viewVersion) - offsetof(UA_ViewDescription, timestamp) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseDescription */ static UA_DataTypeMember BrowseDescription_members[6] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BrowseDirection") /* .memberName */ - UA_TYPES_BROWSEDIRECTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSEDIRECTION], /* .memberType */ offsetof(UA_BrowseDescription, browseDirection) - offsetof(UA_BrowseDescription, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReferenceTypeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_BrowseDescription, referenceTypeId) - offsetof(UA_BrowseDescription, browseDirection) - sizeof(UA_BrowseDirection), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IncludeSubtypes") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_BrowseDescription, includeSubtypes) - offsetof(UA_BrowseDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodeClassMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_BrowseDescription, nodeClassMask) - offsetof(UA_BrowseDescription, includeSubtypes) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ResultMask") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_BrowseDescription, resultMask) - offsetof(UA_BrowseDescription, nodeClassMask) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseResultMask */ @@ -13258,419 +12129,373 @@ static UA_DataTypeMember BrowseDescription_members[6] = { static UA_DataTypeMember ReferenceDescription_members[7] = { { UA_TYPENAME("ReferenceTypeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsForward") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ReferenceDescription, isForward) - offsetof(UA_ReferenceDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ offsetof(UA_ReferenceDescription, nodeId) - offsetof(UA_ReferenceDescription, isForward) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BrowseName") /* .memberName */ - UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ offsetof(UA_ReferenceDescription, browseName) - offsetof(UA_ReferenceDescription, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ReferenceDescription, displayName) - offsetof(UA_ReferenceDescription, browseName) - sizeof(UA_QualifiedName), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodeClass") /* .memberName */ - UA_TYPES_NODECLASS, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */ offsetof(UA_ReferenceDescription, nodeClass) - offsetof(UA_ReferenceDescription, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TypeDefinition") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ offsetof(UA_ReferenceDescription, typeDefinition) - offsetof(UA_ReferenceDescription, nodeClass) - sizeof(UA_NodeClass), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseResult */ static UA_DataTypeMember BrowseResult_members[3] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ContinuationPoint") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_BrowseResult, continuationPoint) - offsetof(UA_BrowseResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("References") /* .memberName */ - UA_TYPES_REFERENCEDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], /* .memberType */ offsetof(UA_BrowseResult, referencesSize) - offsetof(UA_BrowseResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseRequest */ static UA_DataTypeMember BrowseRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("View") /* .memberName */ - UA_TYPES_VIEWDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], /* .memberType */ offsetof(UA_BrowseRequest, view) - offsetof(UA_BrowseRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedMaxReferencesPerNode") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - offsetof(UA_BrowseRequest, view) - sizeof(UA_ViewDescription), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToBrowse") /* .memberName */ - UA_TYPES_BROWSEDESCRIPTION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], /* .memberType */ offsetof(UA_BrowseRequest, nodesToBrowseSize) - offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseResponse */ static UA_DataTypeMember BrowseResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_BROWSERESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */ offsetof(UA_BrowseResponse, resultsSize) - offsetof(UA_BrowseResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_BrowseResponse, diagnosticInfosSize) - offsetof(UA_BrowseResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseNextRequest */ static UA_DataTypeMember BrowseNextRequest_members[3] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - offsetof(UA_BrowseNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ContinuationPoints") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_BrowseNextRequest, continuationPointsSize) - offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowseNextResponse */ static UA_DataTypeMember BrowseNextResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_BROWSERESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */ offsetof(UA_BrowseNextResponse, resultsSize) - offsetof(UA_BrowseNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_BrowseNextResponse, diagnosticInfosSize) - offsetof(UA_BrowseNextResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RelativePathElement */ static UA_DataTypeMember RelativePathElement_members[4] = { { UA_TYPENAME("ReferenceTypeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsInverse") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_RelativePathElement, isInverse) - offsetof(UA_RelativePathElement, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IncludeSubtypes") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_RelativePathElement, includeSubtypes) - offsetof(UA_RelativePathElement, isInverse) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TargetName") /* .memberName */ - UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ offsetof(UA_RelativePathElement, targetName) - offsetof(UA_RelativePathElement, includeSubtypes) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RelativePath */ static UA_DataTypeMember RelativePath_members[1] = { { UA_TYPENAME("Elements") /* .memberName */ - UA_TYPES_RELATIVEPATHELEMENT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowsePath */ static UA_DataTypeMember BrowsePath_members[2] = { { UA_TYPENAME("StartingNode") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RelativePath") /* .memberName */ - UA_TYPES_RELATIVEPATH, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */ offsetof(UA_BrowsePath, relativePath) - offsetof(UA_BrowsePath, startingNode) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowsePathTarget */ static UA_DataTypeMember BrowsePathTarget_members[2] = { { UA_TYPENAME("TargetId") /* .memberName */ - UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RemainingPathIndex") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_BrowsePathTarget, remainingPathIndex) - offsetof(UA_BrowsePathTarget, targetId) - sizeof(UA_ExpandedNodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BrowsePathResult */ static UA_DataTypeMember BrowsePathResult_members[2] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Targets") /* .memberName */ - UA_TYPES_BROWSEPATHTARGET, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], /* .memberType */ offsetof(UA_BrowsePathResult, targetsSize) - offsetof(UA_BrowsePathResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* TranslateBrowsePathsToNodeIdsRequest */ static UA_DataTypeMember TranslateBrowsePathsToNodeIdsRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BrowsePaths") /* .memberName */ - UA_TYPES_BROWSEPATH, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSEPATH], /* .memberType */ offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, browsePathsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* TranslateBrowsePathsToNodeIdsResponse */ static UA_DataTypeMember TranslateBrowsePathsToNodeIdsResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_BROWSEPATHRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BROWSEPATHRESULT], /* .memberType */ offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, resultsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, diagnosticInfosSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RegisterNodesRequest */ static UA_DataTypeMember RegisterNodesRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToRegister") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_RegisterNodesRequest, nodesToRegisterSize) - offsetof(UA_RegisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RegisterNodesResponse */ static UA_DataTypeMember RegisterNodesResponse_members[2] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RegisteredNodeIds") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_RegisterNodesResponse, registeredNodeIdsSize) - offsetof(UA_RegisterNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* UnregisterNodesRequest */ static UA_DataTypeMember UnregisterNodesRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToUnregister") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_UnregisterNodesRequest, nodesToUnregisterSize) - offsetof(UA_UnregisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* UnregisterNodesResponse */ static UA_DataTypeMember UnregisterNodesResponse_members[1] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* FilterOperator */ @@ -13680,179 +12505,157 @@ static UA_DataTypeMember UnregisterNodesResponse_members[1] = { static UA_DataTypeMember ContentFilterElement_members[2] = { { UA_TYPENAME("FilterOperator") /* .memberName */ - UA_TYPES_FILTEROPERATOR, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_FILTEROPERATOR], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("FilterOperands") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_ContentFilterElement, filterOperandsSize) - offsetof(UA_ContentFilterElement, filterOperator) - sizeof(UA_FilterOperator), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ContentFilter */ static UA_DataTypeMember ContentFilter_members[1] = { { UA_TYPENAME("Elements") /* .memberName */ - UA_TYPES_CONTENTFILTERELEMENT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; -/* FilterOperand */ -#define FilterOperand_members NULL - /* ElementOperand */ static UA_DataTypeMember ElementOperand_members[1] = { { UA_TYPENAME("Index") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* LiteralOperand */ static UA_DataTypeMember LiteralOperand_members[1] = { { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AttributeOperand */ static UA_DataTypeMember AttributeOperand_members[5] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Alias") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_AttributeOperand, alias) - offsetof(UA_AttributeOperand, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BrowsePath") /* .memberName */ - UA_TYPES_RELATIVEPATH, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */ offsetof(UA_AttributeOperand, browsePath) - offsetof(UA_AttributeOperand, alias) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AttributeId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_AttributeOperand, attributeId) - offsetof(UA_AttributeOperand, browsePath) - sizeof(UA_RelativePath), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IndexRange") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_AttributeOperand, indexRange) - offsetof(UA_AttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SimpleAttributeOperand */ static UA_DataTypeMember SimpleAttributeOperand_members[4] = { { UA_TYPENAME("TypeDefinitionId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BrowsePath") /* .memberName */ - UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ offsetof(UA_SimpleAttributeOperand, browsePathSize) - offsetof(UA_SimpleAttributeOperand, typeDefinitionId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AttributeId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SimpleAttributeOperand, attributeId) - offsetof(UA_SimpleAttributeOperand, browsePath) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IndexRange") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_SimpleAttributeOperand, indexRange) - offsetof(UA_SimpleAttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ContentFilterElementResult */ static UA_DataTypeMember ContentFilterElementResult_members[3] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("OperandStatusCodes") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_ContentFilterElementResult, operandStatusCodesSize) - offsetof(UA_ContentFilterElementResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("OperandDiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_ContentFilterElementResult, operandDiagnosticInfosSize) - offsetof(UA_ContentFilterElementResult, operandStatusCodes) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ContentFilterResult */ static UA_DataTypeMember ContentFilterResult_members[2] = { { UA_TYPENAME("ElementResults") /* .memberName */ - UA_TYPES_CONTENTFILTERELEMENTRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ElementDiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_ContentFilterResult, elementDiagnosticInfosSize) - offsetof(UA_ContentFilterResult, elementResults) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* TimestampsToReturn */ @@ -13862,383 +12665,340 @@ static UA_DataTypeMember ContentFilterResult_members[2] = { static UA_DataTypeMember ReadValueId_members[4] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AttributeId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ReadValueId, attributeId) - offsetof(UA_ReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IndexRange") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ReadValueId, indexRange) - offsetof(UA_ReadValueId, attributeId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DataEncoding") /* .memberName */ - UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ offsetof(UA_ReadValueId, dataEncoding) - offsetof(UA_ReadValueId, indexRange) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReadRequest */ static UA_DataTypeMember ReadRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxAge") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_ReadRequest, maxAge) - offsetof(UA_ReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TimestampsToReturn") /* .memberName */ - UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ offsetof(UA_ReadRequest, timestampsToReturn) - offsetof(UA_ReadRequest, maxAge) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToRead") /* .memberName */ - UA_TYPES_READVALUEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */ offsetof(UA_ReadRequest, nodesToReadSize) - offsetof(UA_ReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReadResponse */ static UA_DataTypeMember ReadResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ offsetof(UA_ReadResponse, resultsSize) - offsetof(UA_ReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_ReadResponse, diagnosticInfosSize) - offsetof(UA_ReadResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryReadValueId */ static UA_DataTypeMember HistoryReadValueId_members[4] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IndexRange") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_HistoryReadValueId, indexRange) - offsetof(UA_HistoryReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DataEncoding") /* .memberName */ - UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ offsetof(UA_HistoryReadValueId, dataEncoding) - offsetof(UA_HistoryReadValueId, indexRange) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ContinuationPoint") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_HistoryReadValueId, continuationPoint) - offsetof(UA_HistoryReadValueId, dataEncoding) - sizeof(UA_QualifiedName), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryReadResult */ static UA_DataTypeMember HistoryReadResult_members[3] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ContinuationPoint") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_HistoryReadResult, continuationPoint) - offsetof(UA_HistoryReadResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("HistoryData") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_HistoryReadResult, historyData) - offsetof(UA_HistoryReadResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReadRawModifiedDetails */ static UA_DataTypeMember ReadRawModifiedDetails_members[5] = { { UA_TYPENAME("IsReadModified") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("StartTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ReadRawModifiedDetails, startTime) - offsetof(UA_ReadRawModifiedDetails, isReadModified) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ReadRawModifiedDetails, endTime) - offsetof(UA_ReadRawModifiedDetails, startTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NumValuesPerNode") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ReadRawModifiedDetails, numValuesPerNode) - offsetof(UA_ReadRawModifiedDetails, endTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReturnBounds") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ReadRawModifiedDetails, returnBounds) - offsetof(UA_ReadRawModifiedDetails, numValuesPerNode) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReadAtTimeDetails */ static UA_DataTypeMember ReadAtTimeDetails_members[2] = { { UA_TYPENAME("ReqTimes") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UseSimpleBounds") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_ReadAtTimeDetails, useSimpleBounds) - offsetof(UA_ReadAtTimeDetails, reqTimes) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryData */ static UA_DataTypeMember HistoryData_members[1] = { { UA_TYPENAME("DataValues") /* .memberName */ - UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryReadRequest */ static UA_DataTypeMember HistoryReadRequest_members[5] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("HistoryReadDetails") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_HistoryReadRequest, historyReadDetails) - offsetof(UA_HistoryReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TimestampsToReturn") /* .memberName */ - UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ offsetof(UA_HistoryReadRequest, timestampsToReturn) - offsetof(UA_HistoryReadRequest, historyReadDetails) - sizeof(UA_ExtensionObject), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_HistoryReadRequest, releaseContinuationPoints) - offsetof(UA_HistoryReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToRead") /* .memberName */ - UA_TYPES_HISTORYREADVALUEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_HISTORYREADVALUEID], /* .memberType */ offsetof(UA_HistoryReadRequest, nodesToReadSize) - offsetof(UA_HistoryReadRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryReadResponse */ static UA_DataTypeMember HistoryReadResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_HISTORYREADRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_HISTORYREADRESULT], /* .memberType */ offsetof(UA_HistoryReadResponse, resultsSize) - offsetof(UA_HistoryReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_HistoryReadResponse, diagnosticInfosSize) - offsetof(UA_HistoryReadResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* WriteValue */ static UA_DataTypeMember WriteValue_members[4] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AttributeId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_WriteValue, attributeId) - offsetof(UA_WriteValue, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IndexRange") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_WriteValue, indexRange) - offsetof(UA_WriteValue, attributeId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ offsetof(UA_WriteValue, value) - offsetof(UA_WriteValue, indexRange) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* WriteRequest */ static UA_DataTypeMember WriteRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NodesToWrite") /* .memberName */ - UA_TYPES_WRITEVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_WRITEVALUE], /* .memberType */ offsetof(UA_WriteRequest, nodesToWriteSize) - offsetof(UA_WriteRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* WriteResponse */ static UA_DataTypeMember WriteResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_WriteResponse, resultsSize) - offsetof(UA_WriteResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_WriteResponse, diagnosticInfosSize) - offsetof(UA_WriteResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryUpdateType */ @@ -14251,243 +13011,216 @@ static UA_DataTypeMember WriteResponse_members[3] = { static UA_DataTypeMember UpdateDataDetails_members[3] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PerformInsertReplace") /* .memberName */ - UA_TYPES_PERFORMUPDATETYPE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], /* .memberType */ offsetof(UA_UpdateDataDetails, performInsertReplace) - offsetof(UA_UpdateDataDetails, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UpdateValues") /* .memberName */ - UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ offsetof(UA_UpdateDataDetails, updateValuesSize) - offsetof(UA_UpdateDataDetails, performInsertReplace) - sizeof(UA_PerformUpdateType), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteRawModifiedDetails */ static UA_DataTypeMember DeleteRawModifiedDetails_members[4] = { { UA_TYPENAME("NodeId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("IsDeleteModified") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_DeleteRawModifiedDetails, isDeleteModified) - offsetof(UA_DeleteRawModifiedDetails, nodeId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("StartTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_DeleteRawModifiedDetails, startTime) - offsetof(UA_DeleteRawModifiedDetails, isDeleteModified) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_DeleteRawModifiedDetails, endTime) - offsetof(UA_DeleteRawModifiedDetails, startTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryUpdateResult */ static UA_DataTypeMember HistoryUpdateResult_members[3] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("OperationResults") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_HistoryUpdateResult, operationResultsSize) - offsetof(UA_HistoryUpdateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_HistoryUpdateResult, diagnosticInfosSize) - offsetof(UA_HistoryUpdateResult, operationResults) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryUpdateRequest */ static UA_DataTypeMember HistoryUpdateRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("HistoryUpdateDetails") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_HistoryUpdateRequest, historyUpdateDetailsSize) - offsetof(UA_HistoryUpdateRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryUpdateResponse */ static UA_DataTypeMember HistoryUpdateResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_HISTORYUPDATERESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT], /* .memberType */ offsetof(UA_HistoryUpdateResponse, resultsSize) - offsetof(UA_HistoryUpdateResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_HistoryUpdateResponse, diagnosticInfosSize) - offsetof(UA_HistoryUpdateResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CallMethodRequest */ static UA_DataTypeMember CallMethodRequest_members[3] = { { UA_TYPENAME("ObjectId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MethodId") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_CallMethodRequest, methodId) - offsetof(UA_CallMethodRequest, objectId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("InputArguments") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ offsetof(UA_CallMethodRequest, inputArgumentsSize) - offsetof(UA_CallMethodRequest, methodId) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CallMethodResult */ static UA_DataTypeMember CallMethodResult_members[4] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("InputArgumentResults") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_CallMethodResult, inputArgumentResultsSize) - offsetof(UA_CallMethodResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("InputArgumentDiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfosSize) - offsetof(UA_CallMethodResult, inputArgumentResults) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("OutputArguments") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ offsetof(UA_CallMethodResult, outputArgumentsSize) - offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfos) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CallRequest */ static UA_DataTypeMember CallRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MethodsToCall") /* .memberName */ - UA_TYPES_CALLMETHODREQUEST, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], /* .memberType */ offsetof(UA_CallRequest, methodsToCallSize) - offsetof(UA_CallRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CallResponse */ static UA_DataTypeMember CallResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_CALLMETHODRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CALLMETHODRESULT], /* .memberType */ offsetof(UA_CallResponse, resultsSize) - offsetof(UA_CallResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_CallResponse, diagnosticInfosSize) - offsetof(UA_CallResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoringMode */ @@ -14503,1229 +13236,1155 @@ static UA_DataTypeMember CallResponse_members[3] = { static UA_DataTypeMember DataChangeFilter_members[3] = { { UA_TYPENAME("Trigger") /* .memberName */ - UA_TYPES_DATACHANGETRIGGER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATACHANGETRIGGER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DeadbandType") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_DataChangeFilter, deadbandType) - offsetof(UA_DataChangeFilter, trigger) - sizeof(UA_DataChangeTrigger), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DeadbandValue") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_DataChangeFilter, deadbandValue) - offsetof(UA_DataChangeFilter, deadbandType) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EventFilter */ static UA_DataTypeMember EventFilter_members[2] = { { UA_TYPENAME("SelectClauses") /* .memberName */ - UA_TYPES_SIMPLEATTRIBUTEOPERAND, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WhereClause") /* .memberName */ - UA_TYPES_CONTENTFILTER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CONTENTFILTER], /* .memberType */ offsetof(UA_EventFilter, whereClause) - offsetof(UA_EventFilter, selectClauses) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AggregateConfiguration */ static UA_DataTypeMember AggregateConfiguration_members[5] = { { UA_TYPENAME("UseServerCapabilitiesDefaults") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TreatUncertainAsBad") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - offsetof(UA_AggregateConfiguration, useServerCapabilitiesDefaults) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PercentDataBad") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_AggregateConfiguration, percentDataBad) - offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PercentDataGood") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_AggregateConfiguration, percentDataGood) - offsetof(UA_AggregateConfiguration, percentDataBad) - sizeof(UA_Byte), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UseSlopedExtrapolation") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_AggregateConfiguration, useSlopedExtrapolation) - offsetof(UA_AggregateConfiguration, percentDataGood) - sizeof(UA_Byte), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AggregateFilter */ static UA_DataTypeMember AggregateFilter_members[4] = { { UA_TYPENAME("StartTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AggregateType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_AggregateFilter, aggregateType) - offsetof(UA_AggregateFilter, startTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ProcessingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_AggregateFilter, processingInterval) - offsetof(UA_AggregateFilter, aggregateType) - sizeof(UA_NodeId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AggregateConfiguration") /* .memberName */ - UA_TYPES_AGGREGATECONFIGURATION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */ offsetof(UA_AggregateFilter, aggregateConfiguration) - offsetof(UA_AggregateFilter, processingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EventFilterResult */ static UA_DataTypeMember EventFilterResult_members[3] = { { UA_TYPENAME("SelectClauseResults") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SelectClauseDiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_EventFilterResult, selectClauseDiagnosticInfosSize) - offsetof(UA_EventFilterResult, selectClauseResults) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("WhereClauseResult") /* .memberName */ - UA_TYPES_CONTENTFILTERRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], /* .memberType */ offsetof(UA_EventFilterResult, whereClauseResult) - offsetof(UA_EventFilterResult, selectClauseDiagnosticInfos) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoringParameters */ static UA_DataTypeMember MonitoringParameters_members[5] = { { UA_TYPENAME("ClientHandle") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SamplingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_MonitoringParameters, samplingInterval) - offsetof(UA_MonitoringParameters, clientHandle) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Filter") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_MonitoringParameters, filter) - offsetof(UA_MonitoringParameters, samplingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("QueueSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_MonitoringParameters, queueSize) - offsetof(UA_MonitoringParameters, filter) - sizeof(UA_ExtensionObject), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiscardOldest") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_MonitoringParameters, discardOldest) - offsetof(UA_MonitoringParameters, queueSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoredItemCreateRequest */ static UA_DataTypeMember MonitoredItemCreateRequest_members[3] = { { UA_TYPENAME("ItemToMonitor") /* .memberName */ - UA_TYPES_READVALUEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MonitoringMode") /* .memberName */ - UA_TYPES_MONITORINGMODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */ offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - offsetof(UA_MonitoredItemCreateRequest, itemToMonitor) - sizeof(UA_ReadValueId), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedParameters") /* .memberName */ - UA_TYPES_MONITORINGPARAMETERS, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */ offsetof(UA_MonitoredItemCreateRequest, requestedParameters) - offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoredItemCreateResult */ static UA_DataTypeMember MonitoredItemCreateResult_members[5] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MonitoredItemId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - offsetof(UA_MonitoredItemCreateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedSamplingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedQueueSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("FilterResult") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_MonitoredItemCreateResult, filterResult) - offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CreateMonitoredItemsRequest */ static UA_DataTypeMember CreateMonitoredItemsRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - offsetof(UA_CreateMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TimestampsToReturn") /* .memberName */ - UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ItemsToCreate") /* .memberName */ - UA_TYPES_MONITOREDITEMCREATEREQUEST, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], /* .memberType */ offsetof(UA_CreateMonitoredItemsRequest, itemsToCreateSize) - offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CreateMonitoredItemsResponse */ static UA_DataTypeMember CreateMonitoredItemsResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_MONITOREDITEMCREATERESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], /* .memberType */ offsetof(UA_CreateMonitoredItemsResponse, resultsSize) - offsetof(UA_CreateMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_CreateMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_CreateMonitoredItemsResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoredItemModifyRequest */ static UA_DataTypeMember MonitoredItemModifyRequest_members[2] = { { UA_TYPENAME("MonitoredItemId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedParameters") /* .memberName */ - UA_TYPES_MONITORINGPARAMETERS, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */ offsetof(UA_MonitoredItemModifyRequest, requestedParameters) - offsetof(UA_MonitoredItemModifyRequest, monitoredItemId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoredItemModifyResult */ static UA_DataTypeMember MonitoredItemModifyResult_members[4] = { { UA_TYPENAME("StatusCode") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedSamplingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemModifyResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedQueueSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("FilterResult") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_MonitoredItemModifyResult, filterResult) - offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ModifyMonitoredItemsRequest */ static UA_DataTypeMember ModifyMonitoredItemsRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - offsetof(UA_ModifyMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TimestampsToReturn") /* .memberName */ - UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ItemsToModify") /* .memberName */ - UA_TYPES_MONITOREDITEMMODIFYREQUEST, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], /* .memberType */ offsetof(UA_ModifyMonitoredItemsRequest, itemsToModifySize) - offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ModifyMonitoredItemsResponse */ static UA_DataTypeMember ModifyMonitoredItemsResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_MONITOREDITEMMODIFYRESULT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT], /* .memberType */ offsetof(UA_ModifyMonitoredItemsResponse, resultsSize) - offsetof(UA_ModifyMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_ModifyMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_ModifyMonitoredItemsResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SetMonitoringModeRequest */ static UA_DataTypeMember SetMonitoringModeRequest_members[4] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetMonitoringModeRequest, subscriptionId) - offsetof(UA_SetMonitoringModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MonitoringMode") /* .memberName */ - UA_TYPES_MONITORINGMODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */ offsetof(UA_SetMonitoringModeRequest, monitoringMode) - offsetof(UA_SetMonitoringModeRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MonitoredItemIds") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetMonitoringModeRequest, monitoredItemIdsSize) - offsetof(UA_SetMonitoringModeRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SetMonitoringModeResponse */ static UA_DataTypeMember SetMonitoringModeResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_SetMonitoringModeResponse, resultsSize) - offsetof(UA_SetMonitoringModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_SetMonitoringModeResponse, diagnosticInfosSize) - offsetof(UA_SetMonitoringModeResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SetTriggeringRequest */ static UA_DataTypeMember SetTriggeringRequest_members[5] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetTriggeringRequest, subscriptionId) - offsetof(UA_SetTriggeringRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("TriggeringItemId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetTriggeringRequest, triggeringItemId) - offsetof(UA_SetTriggeringRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("LinksToAdd") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetTriggeringRequest, linksToAddSize) - offsetof(UA_SetTriggeringRequest, triggeringItemId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("LinksToRemove") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetTriggeringRequest, linksToRemoveSize) - offsetof(UA_SetTriggeringRequest, linksToAdd) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SetTriggeringResponse */ static UA_DataTypeMember SetTriggeringResponse_members[5] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AddResults") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_SetTriggeringResponse, addResultsSize) - offsetof(UA_SetTriggeringResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AddDiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_SetTriggeringResponse, addDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, addResults) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RemoveResults") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_SetTriggeringResponse, removeResultsSize) - offsetof(UA_SetTriggeringResponse, addDiagnosticInfos) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RemoveDiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_SetTriggeringResponse, removeDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, removeResults) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteMonitoredItemsRequest */ static UA_DataTypeMember DeleteMonitoredItemsRequest_members[3] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - offsetof(UA_DeleteMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MonitoredItemIds") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_DeleteMonitoredItemsRequest, monitoredItemIdsSize) - offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteMonitoredItemsResponse */ static UA_DataTypeMember DeleteMonitoredItemsResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_DeleteMonitoredItemsResponse, resultsSize) - offsetof(UA_DeleteMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_DeleteMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_DeleteMonitoredItemsResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CreateSubscriptionRequest */ static UA_DataTypeMember CreateSubscriptionRequest_members[7] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedPublishingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - offsetof(UA_CreateSubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedLifetimeCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PublishingEnabled") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Priority") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_CreateSubscriptionRequest, priority) - offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* CreateSubscriptionResponse */ static UA_DataTypeMember CreateSubscriptionResponse_members[5] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSubscriptionResponse, subscriptionId) - offsetof(UA_CreateSubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedPublishingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - offsetof(UA_CreateSubscriptionResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedLifetimeCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_CreateSubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ModifySubscriptionRequest */ static UA_DataTypeMember ModifySubscriptionRequest_members[7] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifySubscriptionRequest, subscriptionId) - offsetof(UA_ModifySubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedPublishingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - offsetof(UA_ModifySubscriptionRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedLifetimeCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Priority") /* .memberName */ - UA_TYPES_BYTE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ offsetof(UA_ModifySubscriptionRequest, priority) - offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ModifySubscriptionResponse */ static UA_DataTypeMember ModifySubscriptionResponse_members[4] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedPublishingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - offsetof(UA_ModifySubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedLifetimeCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ModifySubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SetPublishingModeRequest */ static UA_DataTypeMember SetPublishingModeRequest_members[3] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PublishingEnabled") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_SetPublishingModeRequest, publishingEnabled) - offsetof(UA_SetPublishingModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionIds") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SetPublishingModeRequest, subscriptionIdsSize) - offsetof(UA_SetPublishingModeRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SetPublishingModeResponse */ static UA_DataTypeMember SetPublishingModeResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_SetPublishingModeResponse, resultsSize) - offsetof(UA_SetPublishingModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_SetPublishingModeResponse, diagnosticInfosSize) - offsetof(UA_SetPublishingModeResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* NotificationMessage */ static UA_DataTypeMember NotificationMessage_members[3] = { { UA_TYPENAME("SequenceNumber") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PublishTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_NotificationMessage, publishTime) - offsetof(UA_NotificationMessage, sequenceNumber) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NotificationData") /* .memberName */ - UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ offsetof(UA_NotificationMessage, notificationDataSize) - offsetof(UA_NotificationMessage, publishTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* MonitoredItemNotification */ static UA_DataTypeMember MonitoredItemNotification_members[2] = { { UA_TYPENAME("ClientHandle") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ offsetof(UA_MonitoredItemNotification, value) - offsetof(UA_MonitoredItemNotification, clientHandle) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EventFieldList */ static UA_DataTypeMember EventFieldList_members[2] = { { UA_TYPENAME("ClientHandle") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EventFields") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ offsetof(UA_EventFieldList, eventFieldsSize) - offsetof(UA_EventFieldList, clientHandle) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryEventFieldList */ static UA_DataTypeMember HistoryEventFieldList_members[1] = { { UA_TYPENAME("EventFields") /* .memberName */ - UA_TYPES_VARIANT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* StatusChangeNotification */ static UA_DataTypeMember StatusChangeNotification_members[2] = { { UA_TYPENAME("Status") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfo") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_StatusChangeNotification, diagnosticInfo) - offsetof(UA_StatusChangeNotification, status) - sizeof(UA_StatusCode), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SubscriptionAcknowledgement */ static UA_DataTypeMember SubscriptionAcknowledgement_members[2] = { { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SequenceNumber") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SubscriptionAcknowledgement, sequenceNumber) - offsetof(UA_SubscriptionAcknowledgement, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* PublishRequest */ static UA_DataTypeMember PublishRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionAcknowledgements") /* .memberName */ - UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT], /* .memberType */ offsetof(UA_PublishRequest, subscriptionAcknowledgementsSize) - offsetof(UA_PublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* PublishResponse */ static UA_DataTypeMember PublishResponse_members[7] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_PublishResponse, subscriptionId) - offsetof(UA_PublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_PublishResponse, availableSequenceNumbersSize) - offsetof(UA_PublishResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MoreNotifications") /* .memberName */ - UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ offsetof(UA_PublishResponse, moreNotifications) - offsetof(UA_PublishResponse, availableSequenceNumbers) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NotificationMessage") /* .memberName */ - UA_TYPES_NOTIFICATIONMESSAGE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */ offsetof(UA_PublishResponse, notificationMessage) - offsetof(UA_PublishResponse, moreNotifications) - sizeof(UA_Boolean), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_PublishResponse, resultsSize) - offsetof(UA_PublishResponse, notificationMessage) - sizeof(UA_NotificationMessage), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_PublishResponse, diagnosticInfosSize) - offsetof(UA_PublishResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RepublishRequest */ static UA_DataTypeMember RepublishRequest_members[3] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_RepublishRequest, subscriptionId) - offsetof(UA_RepublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RetransmitSequenceNumber") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_RepublishRequest, retransmitSequenceNumber) - offsetof(UA_RepublishRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RepublishResponse */ static UA_DataTypeMember RepublishResponse_members[2] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("NotificationMessage") /* .memberName */ - UA_TYPES_NOTIFICATIONMESSAGE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */ offsetof(UA_RepublishResponse, notificationMessage) - offsetof(UA_RepublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ +},}; + +/* TransferResult */ +static UA_DataTypeMember TransferResult_members[2] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TransferResult, availableSequenceNumbersSize) - offsetof(UA_TransferResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* TransferSubscriptionsRequest */ +static UA_DataTypeMember TransferSubscriptionsRequest_members[3] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionIds") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TransferSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_TransferSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SendInitialValues") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_TransferSubscriptionsRequest, sendInitialValues) - offsetof(UA_TransferSubscriptionsRequest, subscriptionIds) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* TransferSubscriptionsResponse */ +static UA_DataTypeMember TransferSubscriptionsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_TRANSFERRESULT], /* .memberType */ + offsetof(UA_TransferSubscriptionsResponse, resultsSize) - offsetof(UA_TransferSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_TransferSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_TransferSubscriptionsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ },}; /* DeleteSubscriptionsRequest */ static UA_DataTypeMember DeleteSubscriptionsRequest_members[2] = { { UA_TYPENAME("RequestHeader") /* .memberName */ - UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SubscriptionIds") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_DeleteSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_DeleteSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DeleteSubscriptionsResponse */ static UA_DataTypeMember DeleteSubscriptionsResponse_members[3] = { { UA_TYPENAME("ResponseHeader") /* .memberName */ - UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Results") /* .memberName */ - UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ offsetof(UA_DeleteSubscriptionsResponse, resultsSize) - offsetof(UA_DeleteSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_DeleteSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_DeleteSubscriptionsResponse, results) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* BuildInfo */ static UA_DataTypeMember BuildInfo_members[6] = { { UA_TYPENAME("ProductUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ManufacturerName") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_BuildInfo, manufacturerName) - offsetof(UA_BuildInfo, productUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ProductName") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_BuildInfo, productName) - offsetof(UA_BuildInfo, manufacturerName) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SoftwareVersion") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_BuildInfo, softwareVersion) - offsetof(UA_BuildInfo, productName) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BuildNumber") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_BuildInfo, buildNumber) - offsetof(UA_BuildInfo, softwareVersion) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BuildDate") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_BuildInfo, buildDate) - offsetof(UA_BuildInfo, buildNumber) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* RedundancySupport */ @@ -15738,204 +14397,180 @@ static UA_DataTypeMember BuildInfo_members[6] = { static UA_DataTypeMember ServerDiagnosticsSummaryDataType_members[12] = { { UA_TYPENAME("ServerViewCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CurrentSessionCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, serverViewCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CumulatedSessionCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityRejectedSessionCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RejectedSessionCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SessionTimeoutCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SessionAbortCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CurrentSubscriptionCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CumulatedSubscriptionCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("PublishingIntervalCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecurityRejectedRequestsCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RejectedRequestsCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ServerStatusDataType */ static UA_DataTypeMember ServerStatusDataType_members[6] = { { UA_TYPENAME("StartTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("CurrentTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ServerStatusDataType, currentTime) - offsetof(UA_ServerStatusDataType, startTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("State") /* .memberName */ - UA_TYPES_SERVERSTATE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_SERVERSTATE], /* .memberType */ offsetof(UA_ServerStatusDataType, state) - offsetof(UA_ServerStatusDataType, currentTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("BuildInfo") /* .memberName */ - UA_TYPES_BUILDINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BUILDINFO], /* .memberType */ offsetof(UA_ServerStatusDataType, buildInfo) - offsetof(UA_ServerStatusDataType, state) - sizeof(UA_ServerState), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SecondsTillShutdown") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_ServerStatusDataType, secondsTillShutdown) - offsetof(UA_ServerStatusDataType, buildInfo) - sizeof(UA_BuildInfo), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ShutdownReason") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_ServerStatusDataType, shutdownReason) - offsetof(UA_ServerStatusDataType, secondsTillShutdown) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* Range */ static UA_DataTypeMember Range_members[2] = { { UA_TYPENAME("Low") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("High") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_Range, high) - offsetof(UA_Range, low) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EUInformation */ static UA_DataTypeMember EUInformation_members[4] = { { UA_TYPENAME("NamespaceUri") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UnitId") /* .memberName */ - UA_TYPES_INT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ offsetof(UA_EUInformation, unitId) - offsetof(UA_EUInformation, namespaceUri) - sizeof(UA_String), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DisplayName") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_EUInformation, displayName) - offsetof(UA_EUInformation, unitId) - sizeof(UA_Int32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Description") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_EUInformation, description) - offsetof(UA_EUInformation, displayName) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AxisScaleEnumeration */ @@ -15945,2989 +14580,2788 @@ static UA_DataTypeMember EUInformation_members[4] = { static UA_DataTypeMember ComplexNumberType_members[2] = { { UA_TYPENAME("Real") /* .memberName */ - UA_TYPES_FLOAT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Imaginary") /* .memberName */ - UA_TYPES_FLOAT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */ offsetof(UA_ComplexNumberType, imaginary) - offsetof(UA_ComplexNumberType, real) - sizeof(UA_Float), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DoubleComplexNumberType */ static UA_DataTypeMember DoubleComplexNumberType_members[2] = { { UA_TYPENAME("Real") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Imaginary") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_DoubleComplexNumberType, imaginary) - offsetof(UA_DoubleComplexNumberType, real) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AxisInformation */ static UA_DataTypeMember AxisInformation_members[5] = { { UA_TYPENAME("EngineeringUnits") /* .memberName */ - UA_TYPES_EUINFORMATION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EUINFORMATION], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EURange") /* .memberName */ - UA_TYPES_RANGE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_RANGE], /* .memberType */ offsetof(UA_AxisInformation, eURange) - offsetof(UA_AxisInformation, engineeringUnits) - sizeof(UA_EUInformation), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Title") /* .memberName */ - UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ offsetof(UA_AxisInformation, title) - offsetof(UA_AxisInformation, eURange) - sizeof(UA_Range), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AxisScaleType") /* .memberName */ - UA_TYPES_AXISSCALEENUMERATION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION], /* .memberType */ offsetof(UA_AxisInformation, axisScaleType) - offsetof(UA_AxisInformation, title) - sizeof(UA_LocalizedText), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AxisSteps") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_AxisInformation, axisStepsSize) - offsetof(UA_AxisInformation, axisScaleType) - sizeof(UA_AxisScaleEnumeration), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* XVType */ static UA_DataTypeMember XVType_members[2] = { { UA_TYPENAME("X") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Value") /* .memberName */ - UA_TYPES_FLOAT, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */ offsetof(UA_XVType, value) - offsetof(UA_XVType, x) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EnumDefinition */ static UA_DataTypeMember EnumDefinition_members[1] = { { UA_TYPENAME("Fields") /* .memberName */ - UA_TYPES_ENUMFIELD, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_ENUMFIELD], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReadEventDetails */ static UA_DataTypeMember ReadEventDetails_members[4] = { { UA_TYPENAME("NumValuesPerNode") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("StartTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ReadEventDetails, startTime) - offsetof(UA_ReadEventDetails, numValuesPerNode) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ReadEventDetails, endTime) - offsetof(UA_ReadEventDetails, startTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Filter") /* .memberName */ - UA_TYPES_EVENTFILTER, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EVENTFILTER], /* .memberType */ offsetof(UA_ReadEventDetails, filter) - offsetof(UA_ReadEventDetails, endTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ReadProcessedDetails */ static UA_DataTypeMember ReadProcessedDetails_members[5] = { { UA_TYPENAME("StartTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ offsetof(UA_ReadProcessedDetails, endTime) - offsetof(UA_ReadProcessedDetails, startTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ProcessingInterval") /* .memberName */ - UA_TYPES_DOUBLE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ offsetof(UA_ReadProcessedDetails, processingInterval) - offsetof(UA_ReadProcessedDetails, endTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AggregateType") /* .memberName */ - UA_TYPES_NODEID, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ offsetof(UA_ReadProcessedDetails, aggregateTypeSize) - offsetof(UA_ReadProcessedDetails, processingInterval) - sizeof(UA_Double), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("AggregateConfiguration") /* .memberName */ - UA_TYPES_AGGREGATECONFIGURATION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */ offsetof(UA_ReadProcessedDetails, aggregateConfiguration) - offsetof(UA_ReadProcessedDetails, aggregateType) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* ModificationInfo */ static UA_DataTypeMember ModificationInfo_members[3] = { { UA_TYPENAME("ModificationTime") /* .memberName */ - UA_TYPES_DATETIME, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UpdateType") /* .memberName */ - UA_TYPES_HISTORYUPDATETYPE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_HISTORYUPDATETYPE], /* .memberType */ offsetof(UA_ModificationInfo, updateType) - offsetof(UA_ModificationInfo, modificationTime) - sizeof(UA_DateTime), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("UserName") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_ModificationInfo, userName) - offsetof(UA_ModificationInfo, updateType) - sizeof(UA_HistoryUpdateType), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryModifiedData */ static UA_DataTypeMember HistoryModifiedData_members[2] = { { UA_TYPENAME("DataValues") /* .memberName */ - UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ModificationInfos") /* .memberName */ - UA_TYPES_MODIFICATIONINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MODIFICATIONINFO], /* .memberType */ offsetof(UA_HistoryModifiedData, modificationInfosSize) - offsetof(UA_HistoryModifiedData, dataValues) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* HistoryEvent */ static UA_DataTypeMember HistoryEvent_members[1] = { { UA_TYPENAME("Events") /* .memberName */ - UA_TYPES_HISTORYEVENTFIELDLIST, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* DataChangeNotification */ static UA_DataTypeMember DataChangeNotification_members[2] = { { UA_TYPENAME("MonitoredItems") /* .memberName */ - UA_TYPES_MONITOREDITEMNOTIFICATION, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("DiagnosticInfos") /* .memberName */ - UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ offsetof(UA_DataChangeNotification, diagnosticInfosSize) - offsetof(UA_DataChangeNotification, monitoredItems) - sizeof(void *), /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* EventNotificationList */ static UA_DataTypeMember EventNotificationList_members[1] = { { UA_TYPENAME("Events") /* .memberName */ - UA_TYPES_EVENTFIELDLIST, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_EVENTFIELDLIST], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ true, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; const UA_DataType UA_TYPES[UA_TYPES_COUNT] = { /* Boolean */ { UA_TYPENAME("Boolean") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {1}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {1LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Boolean), /* .memSize */ - UA_TYPES_BOOLEAN, /* .typeIndex */ UA_DATATYPEKIND_BOOLEAN, /* .typeKind */ true, /* .pointerFree */ - true, /* .overlayable */ + false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Boolean_members /* .members */ + Boolean_members /* .members */ }, /* SByte */ { UA_TYPENAME("SByte") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {2}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {2LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_SByte), /* .memSize */ - UA_TYPES_SBYTE, /* .typeIndex */ UA_DATATYPEKIND_SBYTE, /* .typeKind */ true, /* .pointerFree */ true, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - SByte_members /* .members */ + SByte_members /* .members */ }, /* Byte */ { UA_TYPENAME("Byte") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {3}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {3LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Byte), /* .memSize */ - UA_TYPES_BYTE, /* .typeIndex */ UA_DATATYPEKIND_BYTE, /* .typeKind */ true, /* .pointerFree */ true, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Byte_members /* .members */ + Byte_members /* .members */ }, /* Int16 */ { UA_TYPENAME("Int16") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {4}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {4LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Int16), /* .memSize */ - UA_TYPES_INT16, /* .typeIndex */ UA_DATATYPEKIND_INT16, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Int16_members /* .members */ + Int16_members /* .members */ }, /* UInt16 */ { UA_TYPENAME("UInt16") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {5}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {5LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_UInt16), /* .memSize */ - UA_TYPES_UINT16, /* .typeIndex */ UA_DATATYPEKIND_UINT16, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - UInt16_members /* .members */ + UInt16_members /* .members */ }, /* Int32 */ { UA_TYPENAME("Int32") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {6}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {6LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Int32), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_INT32, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Int32_members /* .members */ + Int32_members /* .members */ }, /* UInt32 */ { UA_TYPENAME("UInt32") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {7}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {7LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_UInt32), /* .memSize */ - UA_TYPES_UINT32, /* .typeIndex */ UA_DATATYPEKIND_UINT32, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - UInt32_members /* .members */ + UInt32_members /* .members */ }, /* Int64 */ { UA_TYPENAME("Int64") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {8}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {8LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Int64), /* .memSize */ - UA_TYPES_INT64, /* .typeIndex */ UA_DATATYPEKIND_INT64, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Int64_members /* .members */ + Int64_members /* .members */ }, /* UInt64 */ { UA_TYPENAME("UInt64") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {9}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {9LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_UInt64), /* .memSize */ - UA_TYPES_UINT64, /* .typeIndex */ UA_DATATYPEKIND_UINT64, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - UInt64_members /* .members */ + UInt64_members /* .members */ }, /* Float */ { UA_TYPENAME("Float") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {10}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {10LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Float), /* .memSize */ - UA_TYPES_FLOAT, /* .typeIndex */ UA_DATATYPEKIND_FLOAT, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Float_members /* .members */ + Float_members /* .members */ }, /* Double */ { UA_TYPENAME("Double") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {11}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Double), /* .memSize */ - UA_TYPES_DOUBLE, /* .typeIndex */ UA_DATATYPEKIND_DOUBLE, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Double_members /* .members */ + Double_members /* .members */ }, /* String */ { UA_TYPENAME("String") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {12}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_String), /* .memSize */ - UA_TYPES_STRING, /* .typeIndex */ UA_DATATYPEKIND_STRING, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - String_members /* .members */ + String_members /* .members */ }, /* DateTime */ { UA_TYPENAME("DateTime") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {13}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {13LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_DateTime), /* .memSize */ - UA_TYPES_DATETIME, /* .typeIndex */ UA_DATATYPEKIND_DATETIME, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - DateTime_members /* .members */ + DateTime_members /* .members */ }, /* Guid */ { UA_TYPENAME("Guid") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {14}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Guid), /* .memSize */ - UA_TYPES_GUID, /* .typeIndex */ UA_DATATYPEKIND_GUID, /* .typeKind */ true, /* .pointerFree */ (UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32))), /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Guid_members /* .members */ + Guid_members /* .members */ }, /* ByteString */ { UA_TYPENAME("ByteString") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {15}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {15LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_ByteString), /* .memSize */ - UA_TYPES_BYTESTRING, /* .typeIndex */ UA_DATATYPEKIND_BYTESTRING, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - ByteString_members /* .members */ + ByteString_members /* .members */ }, /* XmlElement */ { UA_TYPENAME("XmlElement") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {16}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {16LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_XmlElement), /* .memSize */ - UA_TYPES_XMLELEMENT, /* .typeIndex */ UA_DATATYPEKIND_XMLELEMENT, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - XmlElement_members /* .members */ + XmlElement_members /* .members */ }, /* NodeId */ { UA_TYPENAME("NodeId") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {17}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {17LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_NodeId), /* .memSize */ - UA_TYPES_NODEID, /* .typeIndex */ UA_DATATYPEKIND_NODEID, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - NodeId_members /* .members */ + NodeId_members /* .members */ }, /* ExpandedNodeId */ { UA_TYPENAME("ExpandedNodeId") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {18}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {18LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_ExpandedNodeId), /* .memSize */ - UA_TYPES_EXPANDEDNODEID, /* .typeIndex */ UA_DATATYPEKIND_EXPANDEDNODEID, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - ExpandedNodeId_members /* .members */ + ExpandedNodeId_members /* .members */ }, /* StatusCode */ { UA_TYPENAME("StatusCode") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {19}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {19LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_StatusCode), /* .memSize */ - UA_TYPES_STATUSCODE, /* .typeIndex */ UA_DATATYPEKIND_STATUSCODE, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - StatusCode_members /* .members */ + StatusCode_members /* .members */ }, /* QualifiedName */ { UA_TYPENAME("QualifiedName") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {20}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {20LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_QualifiedName), /* .memSize */ - UA_TYPES_QUALIFIEDNAME, /* .typeIndex */ UA_DATATYPEKIND_QUALIFIEDNAME, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - QualifiedName_members /* .members */ + QualifiedName_members /* .members */ }, /* LocalizedText */ { UA_TYPENAME("LocalizedText") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {21}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {21LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_LocalizedText), /* .memSize */ - UA_TYPES_LOCALIZEDTEXT, /* .typeIndex */ UA_DATATYPEKIND_LOCALIZEDTEXT, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - LocalizedText_members /* .members */ + LocalizedText_members /* .members */ }, /* ExtensionObject */ { UA_TYPENAME("ExtensionObject") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {22}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {22LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_ExtensionObject), /* .memSize */ - UA_TYPES_EXTENSIONOBJECT, /* .typeIndex */ UA_DATATYPEKIND_EXTENSIONOBJECT, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - ExtensionObject_members /* .members */ + ExtensionObject_members /* .members */ }, /* DataValue */ { UA_TYPENAME("DataValue") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {23}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {23LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_DataValue), /* .memSize */ - UA_TYPES_DATAVALUE, /* .typeIndex */ UA_DATATYPEKIND_DATAVALUE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - DataValue_members /* .members */ + DataValue_members /* .members */ }, /* Variant */ { UA_TYPENAME("Variant") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {24}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {24LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Variant), /* .memSize */ - UA_TYPES_VARIANT, /* .typeIndex */ UA_DATATYPEKIND_VARIANT, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Variant_members /* .members */ + Variant_members /* .members */ }, /* DiagnosticInfo */ { UA_TYPENAME("DiagnosticInfo") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {25}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {25LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_DiagnosticInfo), /* .memSize */ - UA_TYPES_DIAGNOSTICINFO, /* .typeIndex */ UA_DATATYPEKIND_DIAGNOSTICINFO, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - DiagnosticInfo_members /* .members */ + DiagnosticInfo_members /* .members */ +}, +/* KeyValuePair */ +{ + UA_TYPENAME("KeyValuePair") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {14533LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14846LU}}, /* .binaryEncodingId */ + sizeof(UA_KeyValuePair), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + KeyValuePair_members /* .members */ }, /* NodeClass */ { UA_TYPENAME("NodeClass") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {257}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {257LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_NodeClass), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - NodeClass_members /* .members */ + NodeClass_members /* .members */ }, /* StructureType */ { UA_TYPENAME("StructureType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {98}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {98LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_StructureType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - StructureType_members /* .members */ + StructureType_members /* .members */ }, /* StructureField */ { UA_TYPENAME("StructureField") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {101}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {101LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14844LU}}, /* .binaryEncodingId */ sizeof(UA_StructureField), /* .memSize */ - UA_TYPES_STRUCTUREFIELD, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 14844, /* .binaryEncodingId */ - StructureField_members /* .members */ + StructureField_members /* .members */ }, /* StructureDefinition */ { UA_TYPENAME("StructureDefinition") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {99}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {99LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {122LU}}, /* .binaryEncodingId */ sizeof(UA_StructureDefinition), /* .memSize */ - UA_TYPES_STRUCTUREDEFINITION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 122, /* .binaryEncodingId */ - StructureDefinition_members /* .members */ + StructureDefinition_members /* .members */ }, /* Argument */ { UA_TYPENAME("Argument") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {296}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {296LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {298LU}}, /* .binaryEncodingId */ sizeof(UA_Argument), /* .memSize */ - UA_TYPES_ARGUMENT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 298, /* .binaryEncodingId */ - Argument_members /* .members */ + Argument_members /* .members */ }, /* EnumValueType */ { UA_TYPENAME("EnumValueType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {7594}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {7594LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {8251LU}}, /* .binaryEncodingId */ sizeof(UA_EnumValueType), /* .memSize */ - UA_TYPES_ENUMVALUETYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 8251, /* .binaryEncodingId */ - EnumValueType_members /* .members */ + EnumValueType_members /* .members */ }, /* EnumField */ { UA_TYPENAME("EnumField") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {102}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {102LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14845LU}}, /* .binaryEncodingId */ sizeof(UA_EnumField), /* .memSize */ - UA_TYPES_ENUMFIELD, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 14845, /* .binaryEncodingId */ - EnumField_members /* .members */ + EnumField_members /* .members */ }, /* Duration */ { UA_TYPENAME("Duration") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {290}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {290LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_Duration), /* .memSize */ - UA_TYPES_DURATION, /* .typeIndex */ UA_DATATYPEKIND_DOUBLE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - Duration_members /* .members */ + Duration_members /* .members */ }, /* UtcTime */ { UA_TYPENAME("UtcTime") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {294}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {294LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_UtcTime), /* .memSize */ - UA_TYPES_UTCTIME, /* .typeIndex */ UA_DATATYPEKIND_DATETIME, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - UtcTime_members /* .members */ + UtcTime_members /* .members */ }, /* LocaleId */ { UA_TYPENAME("LocaleId") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {295}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {295LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_LocaleId), /* .memSize */ - UA_TYPES_LOCALEID, /* .typeIndex */ UA_DATATYPEKIND_STRING, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - LocaleId_members /* .members */ + LocaleId_members /* .members */ }, /* TimeZoneDataType */ { UA_TYPENAME("TimeZoneDataType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {8912}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {8912LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {8917LU}}, /* .binaryEncodingId */ sizeof(UA_TimeZoneDataType), /* .memSize */ - UA_TYPES_TIMEZONEDATATYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 8917, /* .binaryEncodingId */ - TimeZoneDataType_members /* .members */ + TimeZoneDataType_members /* .members */ }, /* ApplicationType */ { UA_TYPENAME("ApplicationType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {307}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {307LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_ApplicationType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - ApplicationType_members /* .members */ + ApplicationType_members /* .members */ }, /* ApplicationDescription */ { UA_TYPENAME("ApplicationDescription") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {308}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {308LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {310LU}}, /* .binaryEncodingId */ sizeof(UA_ApplicationDescription), /* .memSize */ - UA_TYPES_APPLICATIONDESCRIPTION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 310, /* .binaryEncodingId */ - ApplicationDescription_members /* .members */ + ApplicationDescription_members /* .members */ }, /* RequestHeader */ { UA_TYPENAME("RequestHeader") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {389}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {389LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {391LU}}, /* .binaryEncodingId */ sizeof(UA_RequestHeader), /* .memSize */ - UA_TYPES_REQUESTHEADER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 391, /* .binaryEncodingId */ - RequestHeader_members /* .members */ + RequestHeader_members /* .members */ }, /* ResponseHeader */ { UA_TYPENAME("ResponseHeader") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {392}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {392LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {394LU}}, /* .binaryEncodingId */ sizeof(UA_ResponseHeader), /* .memSize */ - UA_TYPES_RESPONSEHEADER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 394, /* .binaryEncodingId */ - ResponseHeader_members /* .members */ + ResponseHeader_members /* .members */ }, /* ServiceFault */ { UA_TYPENAME("ServiceFault") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {395}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {395LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {397LU}}, /* .binaryEncodingId */ sizeof(UA_ServiceFault), /* .memSize */ - UA_TYPES_SERVICEFAULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 397, /* .binaryEncodingId */ - ServiceFault_members /* .members */ + ServiceFault_members /* .members */ }, /* FindServersRequest */ { UA_TYPENAME("FindServersRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {420}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {420LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {422LU}}, /* .binaryEncodingId */ sizeof(UA_FindServersRequest), /* .memSize */ - UA_TYPES_FINDSERVERSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 422, /* .binaryEncodingId */ - FindServersRequest_members /* .members */ + FindServersRequest_members /* .members */ }, /* FindServersResponse */ { UA_TYPENAME("FindServersResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {423}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {423LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {425LU}}, /* .binaryEncodingId */ sizeof(UA_FindServersResponse), /* .memSize */ - UA_TYPES_FINDSERVERSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 425, /* .binaryEncodingId */ - FindServersResponse_members /* .members */ + FindServersResponse_members /* .members */ }, /* MessageSecurityMode */ { UA_TYPENAME("MessageSecurityMode") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {302}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {302LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_MessageSecurityMode), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - MessageSecurityMode_members /* .members */ + MessageSecurityMode_members /* .members */ }, /* UserTokenType */ { UA_TYPENAME("UserTokenType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {303}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {303LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_UserTokenType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - UserTokenType_members /* .members */ + UserTokenType_members /* .members */ }, /* UserTokenPolicy */ { UA_TYPENAME("UserTokenPolicy") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {304}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {304LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {306LU}}, /* .binaryEncodingId */ sizeof(UA_UserTokenPolicy), /* .memSize */ - UA_TYPES_USERTOKENPOLICY, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 306, /* .binaryEncodingId */ - UserTokenPolicy_members /* .members */ + UserTokenPolicy_members /* .members */ }, /* EndpointDescription */ { UA_TYPENAME("EndpointDescription") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {312}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {312LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {314LU}}, /* .binaryEncodingId */ sizeof(UA_EndpointDescription), /* .memSize */ - UA_TYPES_ENDPOINTDESCRIPTION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 8, /* .membersSize */ - 314, /* .binaryEncodingId */ - EndpointDescription_members /* .members */ + EndpointDescription_members /* .members */ }, /* GetEndpointsRequest */ { UA_TYPENAME("GetEndpointsRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {426}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {426LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {428LU}}, /* .binaryEncodingId */ sizeof(UA_GetEndpointsRequest), /* .memSize */ - UA_TYPES_GETENDPOINTSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 428, /* .binaryEncodingId */ - GetEndpointsRequest_members /* .members */ + GetEndpointsRequest_members /* .members */ }, /* GetEndpointsResponse */ { UA_TYPENAME("GetEndpointsResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {429}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {429LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {431LU}}, /* .binaryEncodingId */ sizeof(UA_GetEndpointsResponse), /* .memSize */ - UA_TYPES_GETENDPOINTSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 431, /* .binaryEncodingId */ - GetEndpointsResponse_members /* .members */ + GetEndpointsResponse_members /* .members */ }, /* SecurityTokenRequestType */ { UA_TYPENAME("SecurityTokenRequestType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {315}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {315LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_SecurityTokenRequestType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - SecurityTokenRequestType_members /* .members */ + SecurityTokenRequestType_members /* .members */ }, /* ChannelSecurityToken */ { UA_TYPENAME("ChannelSecurityToken") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {441}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {441LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {443LU}}, /* .binaryEncodingId */ sizeof(UA_ChannelSecurityToken), /* .memSize */ - UA_TYPES_CHANNELSECURITYTOKEN, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 443, /* .binaryEncodingId */ - ChannelSecurityToken_members /* .members */ + ChannelSecurityToken_members /* .members */ }, /* OpenSecureChannelRequest */ { UA_TYPENAME("OpenSecureChannelRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {444}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {444LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {446LU}}, /* .binaryEncodingId */ sizeof(UA_OpenSecureChannelRequest), /* .memSize */ - UA_TYPES_OPENSECURECHANNELREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 446, /* .binaryEncodingId */ - OpenSecureChannelRequest_members /* .members */ + OpenSecureChannelRequest_members /* .members */ }, /* OpenSecureChannelResponse */ { UA_TYPENAME("OpenSecureChannelResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {447}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {447LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {449LU}}, /* .binaryEncodingId */ sizeof(UA_OpenSecureChannelResponse), /* .memSize */ - UA_TYPES_OPENSECURECHANNELRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 449, /* .binaryEncodingId */ - OpenSecureChannelResponse_members /* .members */ + OpenSecureChannelResponse_members /* .members */ }, /* CloseSecureChannelRequest */ { UA_TYPENAME("CloseSecureChannelRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {450}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {450LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {452LU}}, /* .binaryEncodingId */ sizeof(UA_CloseSecureChannelRequest), /* .memSize */ - UA_TYPES_CLOSESECURECHANNELREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 452, /* .binaryEncodingId */ - CloseSecureChannelRequest_members /* .members */ + CloseSecureChannelRequest_members /* .members */ }, /* CloseSecureChannelResponse */ { UA_TYPENAME("CloseSecureChannelResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {453}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {453LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {455LU}}, /* .binaryEncodingId */ sizeof(UA_CloseSecureChannelResponse), /* .memSize */ - UA_TYPES_CLOSESECURECHANNELRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 455, /* .binaryEncodingId */ - CloseSecureChannelResponse_members /* .members */ + CloseSecureChannelResponse_members /* .members */ }, /* SignedSoftwareCertificate */ { UA_TYPENAME("SignedSoftwareCertificate") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {344}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {344LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {346LU}}, /* .binaryEncodingId */ sizeof(UA_SignedSoftwareCertificate), /* .memSize */ - UA_TYPES_SIGNEDSOFTWARECERTIFICATE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 346, /* .binaryEncodingId */ - SignedSoftwareCertificate_members /* .members */ + SignedSoftwareCertificate_members /* .members */ }, /* SignatureData */ { UA_TYPENAME("SignatureData") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {456}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {456LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {458LU}}, /* .binaryEncodingId */ sizeof(UA_SignatureData), /* .memSize */ - UA_TYPES_SIGNATUREDATA, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 458, /* .binaryEncodingId */ - SignatureData_members /* .members */ + SignatureData_members /* .members */ }, /* CreateSessionRequest */ { UA_TYPENAME("CreateSessionRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {459}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {459LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {461LU}}, /* .binaryEncodingId */ sizeof(UA_CreateSessionRequest), /* .memSize */ - UA_TYPES_CREATESESSIONREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 9, /* .membersSize */ - 461, /* .binaryEncodingId */ - CreateSessionRequest_members /* .members */ + CreateSessionRequest_members /* .members */ }, /* CreateSessionResponse */ { UA_TYPENAME("CreateSessionResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {462}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {462LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {464LU}}, /* .binaryEncodingId */ sizeof(UA_CreateSessionResponse), /* .memSize */ - UA_TYPES_CREATESESSIONRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 10, /* .membersSize */ - 464, /* .binaryEncodingId */ - CreateSessionResponse_members /* .members */ + CreateSessionResponse_members /* .members */ }, /* UserIdentityToken */ { UA_TYPENAME("UserIdentityToken") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {316}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {316LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {318LU}}, /* .binaryEncodingId */ sizeof(UA_UserIdentityToken), /* .memSize */ - UA_TYPES_USERIDENTITYTOKEN, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 318, /* .binaryEncodingId */ - UserIdentityToken_members /* .members */ + UserIdentityToken_members /* .members */ }, /* AnonymousIdentityToken */ { UA_TYPENAME("AnonymousIdentityToken") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {319}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {319LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {321LU}}, /* .binaryEncodingId */ sizeof(UA_AnonymousIdentityToken), /* .memSize */ - UA_TYPES_ANONYMOUSIDENTITYTOKEN, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 321, /* .binaryEncodingId */ - AnonymousIdentityToken_members /* .members */ + AnonymousIdentityToken_members /* .members */ }, /* UserNameIdentityToken */ { UA_TYPENAME("UserNameIdentityToken") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {322}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {322LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {324LU}}, /* .binaryEncodingId */ sizeof(UA_UserNameIdentityToken), /* .memSize */ - UA_TYPES_USERNAMEIDENTITYTOKEN, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 324, /* .binaryEncodingId */ - UserNameIdentityToken_members /* .members */ + UserNameIdentityToken_members /* .members */ }, /* X509IdentityToken */ { UA_TYPENAME("X509IdentityToken") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {325}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {325LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {327LU}}, /* .binaryEncodingId */ sizeof(UA_X509IdentityToken), /* .memSize */ - UA_TYPES_X509IDENTITYTOKEN, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 327, /* .binaryEncodingId */ - X509IdentityToken_members /* .members */ + X509IdentityToken_members /* .members */ }, /* IssuedIdentityToken */ { UA_TYPENAME("IssuedIdentityToken") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {938}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {938LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {940LU}}, /* .binaryEncodingId */ sizeof(UA_IssuedIdentityToken), /* .memSize */ - UA_TYPES_ISSUEDIDENTITYTOKEN, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 940, /* .binaryEncodingId */ - IssuedIdentityToken_members /* .members */ + IssuedIdentityToken_members /* .members */ }, /* ActivateSessionRequest */ { UA_TYPENAME("ActivateSessionRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {465}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {465LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {467LU}}, /* .binaryEncodingId */ sizeof(UA_ActivateSessionRequest), /* .memSize */ - UA_TYPES_ACTIVATESESSIONREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 467, /* .binaryEncodingId */ - ActivateSessionRequest_members /* .members */ + ActivateSessionRequest_members /* .members */ }, /* ActivateSessionResponse */ { UA_TYPENAME("ActivateSessionResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {468}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {468LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {470LU}}, /* .binaryEncodingId */ sizeof(UA_ActivateSessionResponse), /* .memSize */ - UA_TYPES_ACTIVATESESSIONRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 470, /* .binaryEncodingId */ - ActivateSessionResponse_members /* .members */ + ActivateSessionResponse_members /* .members */ }, /* CloseSessionRequest */ { UA_TYPENAME("CloseSessionRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {471}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {471LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {473LU}}, /* .binaryEncodingId */ sizeof(UA_CloseSessionRequest), /* .memSize */ - UA_TYPES_CLOSESESSIONREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 473, /* .binaryEncodingId */ - CloseSessionRequest_members /* .members */ + CloseSessionRequest_members /* .members */ }, /* CloseSessionResponse */ { UA_TYPENAME("CloseSessionResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {474}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {474LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {476LU}}, /* .binaryEncodingId */ sizeof(UA_CloseSessionResponse), /* .memSize */ - UA_TYPES_CLOSESESSIONRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 476, /* .binaryEncodingId */ - CloseSessionResponse_members /* .members */ + CloseSessionResponse_members /* .members */ }, /* NodeAttributesMask */ { UA_TYPENAME("NodeAttributesMask") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {348}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {348LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_NodeAttributesMask), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - NodeAttributesMask_members /* .members */ + NodeAttributesMask_members /* .members */ }, /* NodeAttributes */ { UA_TYPENAME("NodeAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {349}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {349LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {351LU}}, /* .binaryEncodingId */ sizeof(UA_NodeAttributes), /* .memSize */ - UA_TYPES_NODEATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 351, /* .binaryEncodingId */ - NodeAttributes_members /* .members */ + NodeAttributes_members /* .members */ }, /* ObjectAttributes */ { UA_TYPENAME("ObjectAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {352}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {352LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {354LU}}, /* .binaryEncodingId */ sizeof(UA_ObjectAttributes), /* .memSize */ - UA_TYPES_OBJECTATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 354, /* .binaryEncodingId */ - ObjectAttributes_members /* .members */ + ObjectAttributes_members /* .members */ }, /* VariableAttributes */ { UA_TYPENAME("VariableAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {355}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {355LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {357LU}}, /* .binaryEncodingId */ sizeof(UA_VariableAttributes), /* .memSize */ - UA_TYPES_VARIABLEATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 13, /* .membersSize */ - 357, /* .binaryEncodingId */ - VariableAttributes_members /* .members */ + VariableAttributes_members /* .members */ }, /* MethodAttributes */ { UA_TYPENAME("MethodAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {358}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {358LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {360LU}}, /* .binaryEncodingId */ sizeof(UA_MethodAttributes), /* .memSize */ - UA_TYPES_METHODATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 360, /* .binaryEncodingId */ - MethodAttributes_members /* .members */ + MethodAttributes_members /* .members */ }, /* ObjectTypeAttributes */ { UA_TYPENAME("ObjectTypeAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {361}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {361LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {363LU}}, /* .binaryEncodingId */ sizeof(UA_ObjectTypeAttributes), /* .memSize */ - UA_TYPES_OBJECTTYPEATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 363, /* .binaryEncodingId */ - ObjectTypeAttributes_members /* .members */ + ObjectTypeAttributes_members /* .members */ }, /* VariableTypeAttributes */ { UA_TYPENAME("VariableTypeAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {364}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {364LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {366LU}}, /* .binaryEncodingId */ sizeof(UA_VariableTypeAttributes), /* .memSize */ - UA_TYPES_VARIABLETYPEATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 10, /* .membersSize */ - 366, /* .binaryEncodingId */ - VariableTypeAttributes_members /* .members */ + VariableTypeAttributes_members /* .members */ }, /* ReferenceTypeAttributes */ { UA_TYPENAME("ReferenceTypeAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {367}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {367LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {369LU}}, /* .binaryEncodingId */ sizeof(UA_ReferenceTypeAttributes), /* .memSize */ - UA_TYPES_REFERENCETYPEATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 8, /* .membersSize */ - 369, /* .binaryEncodingId */ - ReferenceTypeAttributes_members /* .members */ + ReferenceTypeAttributes_members /* .members */ }, /* DataTypeAttributes */ { UA_TYPENAME("DataTypeAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {370}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {370LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {372LU}}, /* .binaryEncodingId */ sizeof(UA_DataTypeAttributes), /* .memSize */ - UA_TYPES_DATATYPEATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 372, /* .binaryEncodingId */ - DataTypeAttributes_members /* .members */ + DataTypeAttributes_members /* .members */ }, /* ViewAttributes */ { UA_TYPENAME("ViewAttributes") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {373}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {373LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {375LU}}, /* .binaryEncodingId */ sizeof(UA_ViewAttributes), /* .memSize */ - UA_TYPES_VIEWATTRIBUTES, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 375, /* .binaryEncodingId */ - ViewAttributes_members /* .members */ + ViewAttributes_members /* .members */ }, /* AddNodesItem */ { UA_TYPENAME("AddNodesItem") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {376}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {376LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {378LU}}, /* .binaryEncodingId */ sizeof(UA_AddNodesItem), /* .memSize */ - UA_TYPES_ADDNODESITEM, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 378, /* .binaryEncodingId */ - AddNodesItem_members /* .members */ + AddNodesItem_members /* .members */ }, /* AddNodesResult */ { UA_TYPENAME("AddNodesResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {483}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {483LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {485LU}}, /* .binaryEncodingId */ sizeof(UA_AddNodesResult), /* .memSize */ - UA_TYPES_ADDNODESRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 485, /* .binaryEncodingId */ - AddNodesResult_members /* .members */ + AddNodesResult_members /* .members */ }, /* AddNodesRequest */ { UA_TYPENAME("AddNodesRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {486}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {486LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {488LU}}, /* .binaryEncodingId */ sizeof(UA_AddNodesRequest), /* .memSize */ - UA_TYPES_ADDNODESREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 488, /* .binaryEncodingId */ - AddNodesRequest_members /* .members */ + AddNodesRequest_members /* .members */ }, /* AddNodesResponse */ { UA_TYPENAME("AddNodesResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {489}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {489LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {491LU}}, /* .binaryEncodingId */ sizeof(UA_AddNodesResponse), /* .memSize */ - UA_TYPES_ADDNODESRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 491, /* .binaryEncodingId */ - AddNodesResponse_members /* .members */ + AddNodesResponse_members /* .members */ }, /* AddReferencesItem */ { UA_TYPENAME("AddReferencesItem") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {379}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {379LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {381LU}}, /* .binaryEncodingId */ sizeof(UA_AddReferencesItem), /* .memSize */ - UA_TYPES_ADDREFERENCESITEM, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 381, /* .binaryEncodingId */ - AddReferencesItem_members /* .members */ + AddReferencesItem_members /* .members */ }, /* AddReferencesRequest */ { UA_TYPENAME("AddReferencesRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {492}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {492LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {494LU}}, /* .binaryEncodingId */ sizeof(UA_AddReferencesRequest), /* .memSize */ - UA_TYPES_ADDREFERENCESREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 494, /* .binaryEncodingId */ - AddReferencesRequest_members /* .members */ + AddReferencesRequest_members /* .members */ }, /* AddReferencesResponse */ { UA_TYPENAME("AddReferencesResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {495}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {495LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {497LU}}, /* .binaryEncodingId */ sizeof(UA_AddReferencesResponse), /* .memSize */ - UA_TYPES_ADDREFERENCESRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 497, /* .binaryEncodingId */ - AddReferencesResponse_members /* .members */ + AddReferencesResponse_members /* .members */ }, /* DeleteNodesItem */ { UA_TYPENAME("DeleteNodesItem") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {382}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {382LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {384LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteNodesItem), /* .memSize */ - UA_TYPES_DELETENODESITEM, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 384, /* .binaryEncodingId */ - DeleteNodesItem_members /* .members */ + DeleteNodesItem_members /* .members */ }, /* DeleteNodesRequest */ { UA_TYPENAME("DeleteNodesRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {498}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {498LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {500LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteNodesRequest), /* .memSize */ - UA_TYPES_DELETENODESREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 500, /* .binaryEncodingId */ - DeleteNodesRequest_members /* .members */ + DeleteNodesRequest_members /* .members */ }, /* DeleteNodesResponse */ { UA_TYPENAME("DeleteNodesResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {501}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {501LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {503LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteNodesResponse), /* .memSize */ - UA_TYPES_DELETENODESRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 503, /* .binaryEncodingId */ - DeleteNodesResponse_members /* .members */ + DeleteNodesResponse_members /* .members */ }, /* DeleteReferencesItem */ { UA_TYPENAME("DeleteReferencesItem") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {385}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {385LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {387LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteReferencesItem), /* .memSize */ - UA_TYPES_DELETEREFERENCESITEM, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 387, /* .binaryEncodingId */ - DeleteReferencesItem_members /* .members */ + DeleteReferencesItem_members /* .members */ }, /* DeleteReferencesRequest */ { UA_TYPENAME("DeleteReferencesRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {504}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {504LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {506LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteReferencesRequest), /* .memSize */ - UA_TYPES_DELETEREFERENCESREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 506, /* .binaryEncodingId */ - DeleteReferencesRequest_members /* .members */ + DeleteReferencesRequest_members /* .members */ }, /* DeleteReferencesResponse */ { UA_TYPENAME("DeleteReferencesResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {507}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {507LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {509LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteReferencesResponse), /* .memSize */ - UA_TYPES_DELETEREFERENCESRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 509, /* .binaryEncodingId */ - DeleteReferencesResponse_members /* .members */ + DeleteReferencesResponse_members /* .members */ }, /* BrowseDirection */ { UA_TYPENAME("BrowseDirection") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {510}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {510LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_BrowseDirection), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - BrowseDirection_members /* .members */ + BrowseDirection_members /* .members */ }, /* ViewDescription */ { UA_TYPENAME("ViewDescription") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {511}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {511LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {513LU}}, /* .binaryEncodingId */ sizeof(UA_ViewDescription), /* .memSize */ - UA_TYPES_VIEWDESCRIPTION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 513, /* .binaryEncodingId */ - ViewDescription_members /* .members */ + ViewDescription_members /* .members */ }, /* BrowseDescription */ { UA_TYPENAME("BrowseDescription") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {514}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {514LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {516LU}}, /* .binaryEncodingId */ sizeof(UA_BrowseDescription), /* .memSize */ - UA_TYPES_BROWSEDESCRIPTION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 516, /* .binaryEncodingId */ - BrowseDescription_members /* .members */ + BrowseDescription_members /* .members */ }, /* BrowseResultMask */ { UA_TYPENAME("BrowseResultMask") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {517}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {517LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_BrowseResultMask), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - BrowseResultMask_members /* .members */ + BrowseResultMask_members /* .members */ }, /* ReferenceDescription */ { UA_TYPENAME("ReferenceDescription") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {518}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {518LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {520LU}}, /* .binaryEncodingId */ sizeof(UA_ReferenceDescription), /* .memSize */ - UA_TYPES_REFERENCEDESCRIPTION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 520, /* .binaryEncodingId */ - ReferenceDescription_members /* .members */ + ReferenceDescription_members /* .members */ }, /* BrowseResult */ { UA_TYPENAME("BrowseResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {522}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {522LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {524LU}}, /* .binaryEncodingId */ sizeof(UA_BrowseResult), /* .memSize */ - UA_TYPES_BROWSERESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 524, /* .binaryEncodingId */ - BrowseResult_members /* .members */ + BrowseResult_members /* .members */ }, /* BrowseRequest */ { UA_TYPENAME("BrowseRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {525}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {525LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {527LU}}, /* .binaryEncodingId */ sizeof(UA_BrowseRequest), /* .memSize */ - UA_TYPES_BROWSEREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 527, /* .binaryEncodingId */ - BrowseRequest_members /* .members */ + BrowseRequest_members /* .members */ }, /* BrowseResponse */ { UA_TYPENAME("BrowseResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {528}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {528LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {530LU}}, /* .binaryEncodingId */ sizeof(UA_BrowseResponse), /* .memSize */ - UA_TYPES_BROWSERESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 530, /* .binaryEncodingId */ - BrowseResponse_members /* .members */ + BrowseResponse_members /* .members */ }, /* BrowseNextRequest */ { UA_TYPENAME("BrowseNextRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {531}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {531LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {533LU}}, /* .binaryEncodingId */ sizeof(UA_BrowseNextRequest), /* .memSize */ - UA_TYPES_BROWSENEXTREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 533, /* .binaryEncodingId */ - BrowseNextRequest_members /* .members */ + BrowseNextRequest_members /* .members */ }, /* BrowseNextResponse */ { UA_TYPENAME("BrowseNextResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {534}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {534LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {536LU}}, /* .binaryEncodingId */ sizeof(UA_BrowseNextResponse), /* .memSize */ - UA_TYPES_BROWSENEXTRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 536, /* .binaryEncodingId */ - BrowseNextResponse_members /* .members */ + BrowseNextResponse_members /* .members */ }, /* RelativePathElement */ { UA_TYPENAME("RelativePathElement") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {537}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {537LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {539LU}}, /* .binaryEncodingId */ sizeof(UA_RelativePathElement), /* .memSize */ - UA_TYPES_RELATIVEPATHELEMENT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 539, /* .binaryEncodingId */ - RelativePathElement_members /* .members */ + RelativePathElement_members /* .members */ }, /* RelativePath */ { UA_TYPENAME("RelativePath") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {540}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {540LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {542LU}}, /* .binaryEncodingId */ sizeof(UA_RelativePath), /* .memSize */ - UA_TYPES_RELATIVEPATH, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 542, /* .binaryEncodingId */ - RelativePath_members /* .members */ + RelativePath_members /* .members */ }, /* BrowsePath */ { UA_TYPENAME("BrowsePath") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {543}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {543LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {545LU}}, /* .binaryEncodingId */ sizeof(UA_BrowsePath), /* .memSize */ - UA_TYPES_BROWSEPATH, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 545, /* .binaryEncodingId */ - BrowsePath_members /* .members */ + BrowsePath_members /* .members */ }, /* BrowsePathTarget */ { UA_TYPENAME("BrowsePathTarget") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {546}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {546LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {548LU}}, /* .binaryEncodingId */ sizeof(UA_BrowsePathTarget), /* .memSize */ - UA_TYPES_BROWSEPATHTARGET, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 548, /* .binaryEncodingId */ - BrowsePathTarget_members /* .members */ + BrowsePathTarget_members /* .members */ }, /* BrowsePathResult */ { UA_TYPENAME("BrowsePathResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {549}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {549LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {551LU}}, /* .binaryEncodingId */ sizeof(UA_BrowsePathResult), /* .memSize */ - UA_TYPES_BROWSEPATHRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 551, /* .binaryEncodingId */ - BrowsePathResult_members /* .members */ + BrowsePathResult_members /* .members */ }, /* TranslateBrowsePathsToNodeIdsRequest */ { UA_TYPENAME("TranslateBrowsePathsToNodeIdsRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {552}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {552LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {554LU}}, /* .binaryEncodingId */ sizeof(UA_TranslateBrowsePathsToNodeIdsRequest), /* .memSize */ - UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 554, /* .binaryEncodingId */ - TranslateBrowsePathsToNodeIdsRequest_members /* .members */ + TranslateBrowsePathsToNodeIdsRequest_members /* .members */ }, /* TranslateBrowsePathsToNodeIdsResponse */ { UA_TYPENAME("TranslateBrowsePathsToNodeIdsResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {555}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {555LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {557LU}}, /* .binaryEncodingId */ sizeof(UA_TranslateBrowsePathsToNodeIdsResponse), /* .memSize */ - UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 557, /* .binaryEncodingId */ - TranslateBrowsePathsToNodeIdsResponse_members /* .members */ + TranslateBrowsePathsToNodeIdsResponse_members /* .members */ }, /* RegisterNodesRequest */ { UA_TYPENAME("RegisterNodesRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {558}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {558LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {560LU}}, /* .binaryEncodingId */ sizeof(UA_RegisterNodesRequest), /* .memSize */ - UA_TYPES_REGISTERNODESREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 560, /* .binaryEncodingId */ - RegisterNodesRequest_members /* .members */ + RegisterNodesRequest_members /* .members */ }, /* RegisterNodesResponse */ { UA_TYPENAME("RegisterNodesResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {561}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {561LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {563LU}}, /* .binaryEncodingId */ sizeof(UA_RegisterNodesResponse), /* .memSize */ - UA_TYPES_REGISTERNODESRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 563, /* .binaryEncodingId */ - RegisterNodesResponse_members /* .members */ + RegisterNodesResponse_members /* .members */ }, /* UnregisterNodesRequest */ { UA_TYPENAME("UnregisterNodesRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {564}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {564LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {566LU}}, /* .binaryEncodingId */ sizeof(UA_UnregisterNodesRequest), /* .memSize */ - UA_TYPES_UNREGISTERNODESREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 566, /* .binaryEncodingId */ - UnregisterNodesRequest_members /* .members */ + UnregisterNodesRequest_members /* .members */ }, /* UnregisterNodesResponse */ { UA_TYPENAME("UnregisterNodesResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {567}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {567LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {569LU}}, /* .binaryEncodingId */ sizeof(UA_UnregisterNodesResponse), /* .memSize */ - UA_TYPES_UNREGISTERNODESRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 569, /* .binaryEncodingId */ - UnregisterNodesResponse_members /* .members */ + UnregisterNodesResponse_members /* .members */ }, /* FilterOperator */ { UA_TYPENAME("FilterOperator") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {576}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {576LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_FilterOperator), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - FilterOperator_members /* .members */ + FilterOperator_members /* .members */ }, /* ContentFilterElement */ { UA_TYPENAME("ContentFilterElement") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {583}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {583LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {585LU}}, /* .binaryEncodingId */ sizeof(UA_ContentFilterElement), /* .memSize */ - UA_TYPES_CONTENTFILTERELEMENT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 585, /* .binaryEncodingId */ - ContentFilterElement_members /* .members */ + ContentFilterElement_members /* .members */ }, /* ContentFilter */ { UA_TYPENAME("ContentFilter") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {586}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {586LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {588LU}}, /* .binaryEncodingId */ sizeof(UA_ContentFilter), /* .memSize */ - UA_TYPES_CONTENTFILTER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 588, /* .binaryEncodingId */ - ContentFilter_members /* .members */ -}, -/* FilterOperand */ -{ - UA_TYPENAME("FilterOperand") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {589}}, /* .typeId */ - sizeof(UA_FilterOperand), /* .memSize */ - UA_TYPES_FILTEROPERAND, /* .typeIndex */ - UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ - true, /* .pointerFree */ - false, /* .overlayable */ - 0, /* .membersSize */ - 591, /* .binaryEncodingId */ - FilterOperand_members /* .members */ + ContentFilter_members /* .members */ }, /* ElementOperand */ { UA_TYPENAME("ElementOperand") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {592}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {592LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {594LU}}, /* .binaryEncodingId */ sizeof(UA_ElementOperand), /* .memSize */ - UA_TYPES_ELEMENTOPERAND, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 594, /* .binaryEncodingId */ - ElementOperand_members /* .members */ + ElementOperand_members /* .members */ }, /* LiteralOperand */ { UA_TYPENAME("LiteralOperand") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {595}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {595LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {597LU}}, /* .binaryEncodingId */ sizeof(UA_LiteralOperand), /* .memSize */ - UA_TYPES_LITERALOPERAND, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 597, /* .binaryEncodingId */ - LiteralOperand_members /* .members */ + LiteralOperand_members /* .members */ }, /* AttributeOperand */ { UA_TYPENAME("AttributeOperand") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {598}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {598LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {600LU}}, /* .binaryEncodingId */ sizeof(UA_AttributeOperand), /* .memSize */ - UA_TYPES_ATTRIBUTEOPERAND, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 600, /* .binaryEncodingId */ - AttributeOperand_members /* .members */ + AttributeOperand_members /* .members */ }, /* SimpleAttributeOperand */ { UA_TYPENAME("SimpleAttributeOperand") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {601}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {601LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {603LU}}, /* .binaryEncodingId */ sizeof(UA_SimpleAttributeOperand), /* .memSize */ - UA_TYPES_SIMPLEATTRIBUTEOPERAND, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 603, /* .binaryEncodingId */ - SimpleAttributeOperand_members /* .members */ + SimpleAttributeOperand_members /* .members */ }, /* ContentFilterElementResult */ { UA_TYPENAME("ContentFilterElementResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {604}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {604LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {606LU}}, /* .binaryEncodingId */ sizeof(UA_ContentFilterElementResult), /* .memSize */ - UA_TYPES_CONTENTFILTERELEMENTRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 606, /* .binaryEncodingId */ - ContentFilterElementResult_members /* .members */ + ContentFilterElementResult_members /* .members */ }, /* ContentFilterResult */ { UA_TYPENAME("ContentFilterResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {607}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {607LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {609LU}}, /* .binaryEncodingId */ sizeof(UA_ContentFilterResult), /* .memSize */ - UA_TYPES_CONTENTFILTERRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 609, /* .binaryEncodingId */ - ContentFilterResult_members /* .members */ + ContentFilterResult_members /* .members */ }, /* TimestampsToReturn */ { UA_TYPENAME("TimestampsToReturn") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {625}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {625LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_TimestampsToReturn), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - TimestampsToReturn_members /* .members */ + TimestampsToReturn_members /* .members */ }, /* ReadValueId */ { UA_TYPENAME("ReadValueId") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {626}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {626LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {628LU}}, /* .binaryEncodingId */ sizeof(UA_ReadValueId), /* .memSize */ - UA_TYPES_READVALUEID, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 628, /* .binaryEncodingId */ - ReadValueId_members /* .members */ + ReadValueId_members /* .members */ }, /* ReadRequest */ { UA_TYPENAME("ReadRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {629}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {629LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {631LU}}, /* .binaryEncodingId */ sizeof(UA_ReadRequest), /* .memSize */ - UA_TYPES_READREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 631, /* .binaryEncodingId */ - ReadRequest_members /* .members */ + ReadRequest_members /* .members */ }, /* ReadResponse */ { UA_TYPENAME("ReadResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {632}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {632LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {634LU}}, /* .binaryEncodingId */ sizeof(UA_ReadResponse), /* .memSize */ - UA_TYPES_READRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 634, /* .binaryEncodingId */ - ReadResponse_members /* .members */ + ReadResponse_members /* .members */ }, /* HistoryReadValueId */ { UA_TYPENAME("HistoryReadValueId") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {635}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {635LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {637LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryReadValueId), /* .memSize */ - UA_TYPES_HISTORYREADVALUEID, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 637, /* .binaryEncodingId */ - HistoryReadValueId_members /* .members */ + HistoryReadValueId_members /* .members */ }, /* HistoryReadResult */ { UA_TYPENAME("HistoryReadResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {638}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {638LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {640LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryReadResult), /* .memSize */ - UA_TYPES_HISTORYREADRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 640, /* .binaryEncodingId */ - HistoryReadResult_members /* .members */ + HistoryReadResult_members /* .members */ }, /* ReadRawModifiedDetails */ { UA_TYPENAME("ReadRawModifiedDetails") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {647}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {647LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {649LU}}, /* .binaryEncodingId */ sizeof(UA_ReadRawModifiedDetails), /* .memSize */ - UA_TYPES_READRAWMODIFIEDDETAILS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 649, /* .binaryEncodingId */ - ReadRawModifiedDetails_members /* .members */ + ReadRawModifiedDetails_members /* .members */ }, /* ReadAtTimeDetails */ { UA_TYPENAME("ReadAtTimeDetails") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {653}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {653LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {655LU}}, /* .binaryEncodingId */ sizeof(UA_ReadAtTimeDetails), /* .memSize */ - UA_TYPES_READATTIMEDETAILS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 655, /* .binaryEncodingId */ - ReadAtTimeDetails_members /* .members */ + ReadAtTimeDetails_members /* .members */ }, /* HistoryData */ { UA_TYPENAME("HistoryData") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {656}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {656LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {658LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryData), /* .memSize */ - UA_TYPES_HISTORYDATA, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 658, /* .binaryEncodingId */ - HistoryData_members /* .members */ + HistoryData_members /* .members */ }, /* HistoryReadRequest */ { UA_TYPENAME("HistoryReadRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {662}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {662LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {664LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryReadRequest), /* .memSize */ - UA_TYPES_HISTORYREADREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 664, /* .binaryEncodingId */ - HistoryReadRequest_members /* .members */ + HistoryReadRequest_members /* .members */ }, /* HistoryReadResponse */ { UA_TYPENAME("HistoryReadResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {665}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {665LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {667LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryReadResponse), /* .memSize */ - UA_TYPES_HISTORYREADRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 667, /* .binaryEncodingId */ - HistoryReadResponse_members /* .members */ + HistoryReadResponse_members /* .members */ }, /* WriteValue */ { UA_TYPENAME("WriteValue") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {668}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {668LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {670LU}}, /* .binaryEncodingId */ sizeof(UA_WriteValue), /* .memSize */ - UA_TYPES_WRITEVALUE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 670, /* .binaryEncodingId */ - WriteValue_members /* .members */ + WriteValue_members /* .members */ }, /* WriteRequest */ { UA_TYPENAME("WriteRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {671}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {671LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {673LU}}, /* .binaryEncodingId */ sizeof(UA_WriteRequest), /* .memSize */ - UA_TYPES_WRITEREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 673, /* .binaryEncodingId */ - WriteRequest_members /* .members */ + WriteRequest_members /* .members */ }, /* WriteResponse */ { UA_TYPENAME("WriteResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {674}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {674LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {676LU}}, /* .binaryEncodingId */ sizeof(UA_WriteResponse), /* .memSize */ - UA_TYPES_WRITERESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 676, /* .binaryEncodingId */ - WriteResponse_members /* .members */ + WriteResponse_members /* .members */ }, /* HistoryUpdateType */ { UA_TYPENAME("HistoryUpdateType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {11234}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11234LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_HistoryUpdateType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - HistoryUpdateType_members /* .members */ + HistoryUpdateType_members /* .members */ }, /* PerformUpdateType */ { UA_TYPENAME("PerformUpdateType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {11293}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11293LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_PerformUpdateType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - PerformUpdateType_members /* .members */ + PerformUpdateType_members /* .members */ }, /* UpdateDataDetails */ { UA_TYPENAME("UpdateDataDetails") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {680}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {680LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {682LU}}, /* .binaryEncodingId */ sizeof(UA_UpdateDataDetails), /* .memSize */ - UA_TYPES_UPDATEDATADETAILS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 682, /* .binaryEncodingId */ - UpdateDataDetails_members /* .members */ + UpdateDataDetails_members /* .members */ }, /* DeleteRawModifiedDetails */ { UA_TYPENAME("DeleteRawModifiedDetails") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {686}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {686LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {688LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteRawModifiedDetails), /* .memSize */ - UA_TYPES_DELETERAWMODIFIEDDETAILS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 688, /* .binaryEncodingId */ - DeleteRawModifiedDetails_members /* .members */ + DeleteRawModifiedDetails_members /* .members */ }, /* HistoryUpdateResult */ { UA_TYPENAME("HistoryUpdateResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {695}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {695LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {697LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryUpdateResult), /* .memSize */ - UA_TYPES_HISTORYUPDATERESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 697, /* .binaryEncodingId */ - HistoryUpdateResult_members /* .members */ + HistoryUpdateResult_members /* .members */ }, /* HistoryUpdateRequest */ { UA_TYPENAME("HistoryUpdateRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {698}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {698LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {700LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryUpdateRequest), /* .memSize */ - UA_TYPES_HISTORYUPDATEREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 700, /* .binaryEncodingId */ - HistoryUpdateRequest_members /* .members */ + HistoryUpdateRequest_members /* .members */ }, /* HistoryUpdateResponse */ { UA_TYPENAME("HistoryUpdateResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {701}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {701LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {703LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryUpdateResponse), /* .memSize */ - UA_TYPES_HISTORYUPDATERESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 703, /* .binaryEncodingId */ - HistoryUpdateResponse_members /* .members */ + HistoryUpdateResponse_members /* .members */ }, /* CallMethodRequest */ { UA_TYPENAME("CallMethodRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {704}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {704LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {706LU}}, /* .binaryEncodingId */ sizeof(UA_CallMethodRequest), /* .memSize */ - UA_TYPES_CALLMETHODREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 706, /* .binaryEncodingId */ - CallMethodRequest_members /* .members */ + CallMethodRequest_members /* .members */ }, /* CallMethodResult */ { UA_TYPENAME("CallMethodResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {707}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {707LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {709LU}}, /* .binaryEncodingId */ sizeof(UA_CallMethodResult), /* .memSize */ - UA_TYPES_CALLMETHODRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 709, /* .binaryEncodingId */ - CallMethodResult_members /* .members */ + CallMethodResult_members /* .members */ }, /* CallRequest */ { UA_TYPENAME("CallRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {710}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {710LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {712LU}}, /* .binaryEncodingId */ sizeof(UA_CallRequest), /* .memSize */ - UA_TYPES_CALLREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 712, /* .binaryEncodingId */ - CallRequest_members /* .members */ + CallRequest_members /* .members */ }, /* CallResponse */ { UA_TYPENAME("CallResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {713}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {713LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {715LU}}, /* .binaryEncodingId */ sizeof(UA_CallResponse), /* .memSize */ - UA_TYPES_CALLRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 715, /* .binaryEncodingId */ - CallResponse_members /* .members */ + CallResponse_members /* .members */ }, /* MonitoringMode */ { UA_TYPENAME("MonitoringMode") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {716}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {716LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_MonitoringMode), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - MonitoringMode_members /* .members */ + MonitoringMode_members /* .members */ }, /* DataChangeTrigger */ { UA_TYPENAME("DataChangeTrigger") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {717}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {717LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_DataChangeTrigger), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - DataChangeTrigger_members /* .members */ + DataChangeTrigger_members /* .members */ }, /* DeadbandType */ { UA_TYPENAME("DeadbandType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {718}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {718LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_DeadbandType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - DeadbandType_members /* .members */ + DeadbandType_members /* .members */ }, /* DataChangeFilter */ { UA_TYPENAME("DataChangeFilter") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {722}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {722LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {724LU}}, /* .binaryEncodingId */ sizeof(UA_DataChangeFilter), /* .memSize */ - UA_TYPES_DATACHANGEFILTER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 724, /* .binaryEncodingId */ - DataChangeFilter_members /* .members */ + DataChangeFilter_members /* .members */ }, /* EventFilter */ { UA_TYPENAME("EventFilter") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {725}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {725LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {727LU}}, /* .binaryEncodingId */ sizeof(UA_EventFilter), /* .memSize */ - UA_TYPES_EVENTFILTER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 727, /* .binaryEncodingId */ - EventFilter_members /* .members */ + EventFilter_members /* .members */ }, /* AggregateConfiguration */ { UA_TYPENAME("AggregateConfiguration") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {948}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {948LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {950LU}}, /* .binaryEncodingId */ sizeof(UA_AggregateConfiguration), /* .memSize */ - UA_TYPES_AGGREGATECONFIGURATION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 950, /* .binaryEncodingId */ - AggregateConfiguration_members /* .members */ + AggregateConfiguration_members /* .members */ }, /* AggregateFilter */ { UA_TYPENAME("AggregateFilter") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {728}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {728LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {730LU}}, /* .binaryEncodingId */ sizeof(UA_AggregateFilter), /* .memSize */ - UA_TYPES_AGGREGATEFILTER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 730, /* .binaryEncodingId */ - AggregateFilter_members /* .members */ + AggregateFilter_members /* .members */ }, /* EventFilterResult */ { UA_TYPENAME("EventFilterResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {734}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {734LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {736LU}}, /* .binaryEncodingId */ sizeof(UA_EventFilterResult), /* .memSize */ - UA_TYPES_EVENTFILTERRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 736, /* .binaryEncodingId */ - EventFilterResult_members /* .members */ + EventFilterResult_members /* .members */ }, /* MonitoringParameters */ { UA_TYPENAME("MonitoringParameters") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {740}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {740LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {742LU}}, /* .binaryEncodingId */ sizeof(UA_MonitoringParameters), /* .memSize */ - UA_TYPES_MONITORINGPARAMETERS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 742, /* .binaryEncodingId */ - MonitoringParameters_members /* .members */ + MonitoringParameters_members /* .members */ }, /* MonitoredItemCreateRequest */ { UA_TYPENAME("MonitoredItemCreateRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {743}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {743LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {745LU}}, /* .binaryEncodingId */ sizeof(UA_MonitoredItemCreateRequest), /* .memSize */ - UA_TYPES_MONITOREDITEMCREATEREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 745, /* .binaryEncodingId */ - MonitoredItemCreateRequest_members /* .members */ + MonitoredItemCreateRequest_members /* .members */ }, /* MonitoredItemCreateResult */ { UA_TYPENAME("MonitoredItemCreateResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {746}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {746LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {748LU}}, /* .binaryEncodingId */ sizeof(UA_MonitoredItemCreateResult), /* .memSize */ - UA_TYPES_MONITOREDITEMCREATERESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 748, /* .binaryEncodingId */ - MonitoredItemCreateResult_members /* .members */ + MonitoredItemCreateResult_members /* .members */ }, /* CreateMonitoredItemsRequest */ { UA_TYPENAME("CreateMonitoredItemsRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {749}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {749LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {751LU}}, /* .binaryEncodingId */ sizeof(UA_CreateMonitoredItemsRequest), /* .memSize */ - UA_TYPES_CREATEMONITOREDITEMSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 751, /* .binaryEncodingId */ - CreateMonitoredItemsRequest_members /* .members */ + CreateMonitoredItemsRequest_members /* .members */ }, /* CreateMonitoredItemsResponse */ { UA_TYPENAME("CreateMonitoredItemsResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {752}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {752LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {754LU}}, /* .binaryEncodingId */ sizeof(UA_CreateMonitoredItemsResponse), /* .memSize */ - UA_TYPES_CREATEMONITOREDITEMSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 754, /* .binaryEncodingId */ - CreateMonitoredItemsResponse_members /* .members */ + CreateMonitoredItemsResponse_members /* .members */ }, /* MonitoredItemModifyRequest */ { UA_TYPENAME("MonitoredItemModifyRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {755}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {755LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {757LU}}, /* .binaryEncodingId */ sizeof(UA_MonitoredItemModifyRequest), /* .memSize */ - UA_TYPES_MONITOREDITEMMODIFYREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 757, /* .binaryEncodingId */ - MonitoredItemModifyRequest_members /* .members */ + MonitoredItemModifyRequest_members /* .members */ }, /* MonitoredItemModifyResult */ { UA_TYPENAME("MonitoredItemModifyResult") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {758}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {758LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {760LU}}, /* .binaryEncodingId */ sizeof(UA_MonitoredItemModifyResult), /* .memSize */ - UA_TYPES_MONITOREDITEMMODIFYRESULT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 760, /* .binaryEncodingId */ - MonitoredItemModifyResult_members /* .members */ + MonitoredItemModifyResult_members /* .members */ }, /* ModifyMonitoredItemsRequest */ { UA_TYPENAME("ModifyMonitoredItemsRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {761}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {761LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {763LU}}, /* .binaryEncodingId */ sizeof(UA_ModifyMonitoredItemsRequest), /* .memSize */ - UA_TYPES_MODIFYMONITOREDITEMSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 763, /* .binaryEncodingId */ - ModifyMonitoredItemsRequest_members /* .members */ + ModifyMonitoredItemsRequest_members /* .members */ }, /* ModifyMonitoredItemsResponse */ { UA_TYPENAME("ModifyMonitoredItemsResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {764}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {764LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {766LU}}, /* .binaryEncodingId */ sizeof(UA_ModifyMonitoredItemsResponse), /* .memSize */ - UA_TYPES_MODIFYMONITOREDITEMSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 766, /* .binaryEncodingId */ - ModifyMonitoredItemsResponse_members /* .members */ + ModifyMonitoredItemsResponse_members /* .members */ }, /* SetMonitoringModeRequest */ { UA_TYPENAME("SetMonitoringModeRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {767}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {767LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {769LU}}, /* .binaryEncodingId */ sizeof(UA_SetMonitoringModeRequest), /* .memSize */ - UA_TYPES_SETMONITORINGMODEREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 769, /* .binaryEncodingId */ - SetMonitoringModeRequest_members /* .members */ + SetMonitoringModeRequest_members /* .members */ }, /* SetMonitoringModeResponse */ { UA_TYPENAME("SetMonitoringModeResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {770}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {770LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {772LU}}, /* .binaryEncodingId */ sizeof(UA_SetMonitoringModeResponse), /* .memSize */ - UA_TYPES_SETMONITORINGMODERESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 772, /* .binaryEncodingId */ - SetMonitoringModeResponse_members /* .members */ + SetMonitoringModeResponse_members /* .members */ }, /* SetTriggeringRequest */ { UA_TYPENAME("SetTriggeringRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {773}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {773LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {775LU}}, /* .binaryEncodingId */ sizeof(UA_SetTriggeringRequest), /* .memSize */ - UA_TYPES_SETTRIGGERINGREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 775, /* .binaryEncodingId */ - SetTriggeringRequest_members /* .members */ + SetTriggeringRequest_members /* .members */ }, /* SetTriggeringResponse */ { UA_TYPENAME("SetTriggeringResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {776}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {776LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {778LU}}, /* .binaryEncodingId */ sizeof(UA_SetTriggeringResponse), /* .memSize */ - UA_TYPES_SETTRIGGERINGRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 778, /* .binaryEncodingId */ - SetTriggeringResponse_members /* .members */ + SetTriggeringResponse_members /* .members */ }, /* DeleteMonitoredItemsRequest */ { UA_TYPENAME("DeleteMonitoredItemsRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {779}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {779LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {781LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteMonitoredItemsRequest), /* .memSize */ - UA_TYPES_DELETEMONITOREDITEMSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 781, /* .binaryEncodingId */ - DeleteMonitoredItemsRequest_members /* .members */ + DeleteMonitoredItemsRequest_members /* .members */ }, /* DeleteMonitoredItemsResponse */ { UA_TYPENAME("DeleteMonitoredItemsResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {782}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {782LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {784LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteMonitoredItemsResponse), /* .memSize */ - UA_TYPES_DELETEMONITOREDITEMSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 784, /* .binaryEncodingId */ - DeleteMonitoredItemsResponse_members /* .members */ + DeleteMonitoredItemsResponse_members /* .members */ }, /* CreateSubscriptionRequest */ { UA_TYPENAME("CreateSubscriptionRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {785}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {785LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {787LU}}, /* .binaryEncodingId */ sizeof(UA_CreateSubscriptionRequest), /* .memSize */ - UA_TYPES_CREATESUBSCRIPTIONREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 787, /* .binaryEncodingId */ - CreateSubscriptionRequest_members /* .members */ + CreateSubscriptionRequest_members /* .members */ }, /* CreateSubscriptionResponse */ { UA_TYPENAME("CreateSubscriptionResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {788}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {788LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {790LU}}, /* .binaryEncodingId */ sizeof(UA_CreateSubscriptionResponse), /* .memSize */ - UA_TYPES_CREATESUBSCRIPTIONRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 790, /* .binaryEncodingId */ - CreateSubscriptionResponse_members /* .members */ + CreateSubscriptionResponse_members /* .members */ }, /* ModifySubscriptionRequest */ { UA_TYPENAME("ModifySubscriptionRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {791}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {791LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {793LU}}, /* .binaryEncodingId */ sizeof(UA_ModifySubscriptionRequest), /* .memSize */ - UA_TYPES_MODIFYSUBSCRIPTIONREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 793, /* .binaryEncodingId */ - ModifySubscriptionRequest_members /* .members */ + ModifySubscriptionRequest_members /* .members */ }, /* ModifySubscriptionResponse */ { UA_TYPENAME("ModifySubscriptionResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {794}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {794LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {796LU}}, /* .binaryEncodingId */ sizeof(UA_ModifySubscriptionResponse), /* .memSize */ - UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 796, /* .binaryEncodingId */ - ModifySubscriptionResponse_members /* .members */ + ModifySubscriptionResponse_members /* .members */ }, /* SetPublishingModeRequest */ { UA_TYPENAME("SetPublishingModeRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {797}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {797LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {799LU}}, /* .binaryEncodingId */ sizeof(UA_SetPublishingModeRequest), /* .memSize */ - UA_TYPES_SETPUBLISHINGMODEREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 799, /* .binaryEncodingId */ - SetPublishingModeRequest_members /* .members */ + SetPublishingModeRequest_members /* .members */ }, /* SetPublishingModeResponse */ { UA_TYPENAME("SetPublishingModeResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {800}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {800LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {802LU}}, /* .binaryEncodingId */ sizeof(UA_SetPublishingModeResponse), /* .memSize */ - UA_TYPES_SETPUBLISHINGMODERESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 802, /* .binaryEncodingId */ - SetPublishingModeResponse_members /* .members */ + SetPublishingModeResponse_members /* .members */ }, /* NotificationMessage */ { UA_TYPENAME("NotificationMessage") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {803}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {803LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {805LU}}, /* .binaryEncodingId */ sizeof(UA_NotificationMessage), /* .memSize */ - UA_TYPES_NOTIFICATIONMESSAGE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 805, /* .binaryEncodingId */ - NotificationMessage_members /* .members */ + NotificationMessage_members /* .members */ }, /* MonitoredItemNotification */ { UA_TYPENAME("MonitoredItemNotification") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {806}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {806LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {808LU}}, /* .binaryEncodingId */ sizeof(UA_MonitoredItemNotification), /* .memSize */ - UA_TYPES_MONITOREDITEMNOTIFICATION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 808, /* .binaryEncodingId */ - MonitoredItemNotification_members /* .members */ + MonitoredItemNotification_members /* .members */ }, /* EventFieldList */ { UA_TYPENAME("EventFieldList") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {917}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {917LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {919LU}}, /* .binaryEncodingId */ sizeof(UA_EventFieldList), /* .memSize */ - UA_TYPES_EVENTFIELDLIST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 919, /* .binaryEncodingId */ - EventFieldList_members /* .members */ + EventFieldList_members /* .members */ }, /* HistoryEventFieldList */ { UA_TYPENAME("HistoryEventFieldList") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {920}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {920LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {922LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryEventFieldList), /* .memSize */ - UA_TYPES_HISTORYEVENTFIELDLIST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 922, /* .binaryEncodingId */ - HistoryEventFieldList_members /* .members */ + HistoryEventFieldList_members /* .members */ }, /* StatusChangeNotification */ { UA_TYPENAME("StatusChangeNotification") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {818}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {818LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {820LU}}, /* .binaryEncodingId */ sizeof(UA_StatusChangeNotification), /* .memSize */ - UA_TYPES_STATUSCHANGENOTIFICATION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 820, /* .binaryEncodingId */ - StatusChangeNotification_members /* .members */ + StatusChangeNotification_members /* .members */ }, /* SubscriptionAcknowledgement */ { UA_TYPENAME("SubscriptionAcknowledgement") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {821}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {821LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {823LU}}, /* .binaryEncodingId */ sizeof(UA_SubscriptionAcknowledgement), /* .memSize */ - UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 823, /* .binaryEncodingId */ - SubscriptionAcknowledgement_members /* .members */ + SubscriptionAcknowledgement_members /* .members */ }, /* PublishRequest */ { UA_TYPENAME("PublishRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {824}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {824LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {826LU}}, /* .binaryEncodingId */ sizeof(UA_PublishRequest), /* .memSize */ - UA_TYPES_PUBLISHREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 826, /* .binaryEncodingId */ - PublishRequest_members /* .members */ + PublishRequest_members /* .members */ }, /* PublishResponse */ { UA_TYPENAME("PublishResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {827}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {827LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {829LU}}, /* .binaryEncodingId */ sizeof(UA_PublishResponse), /* .memSize */ - UA_TYPES_PUBLISHRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 7, /* .membersSize */ - 829, /* .binaryEncodingId */ - PublishResponse_members /* .members */ + PublishResponse_members /* .members */ }, /* RepublishRequest */ { UA_TYPENAME("RepublishRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {830}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {830LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {832LU}}, /* .binaryEncodingId */ sizeof(UA_RepublishRequest), /* .memSize */ - UA_TYPES_REPUBLISHREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 832, /* .binaryEncodingId */ - RepublishRequest_members /* .members */ + RepublishRequest_members /* .members */ }, /* RepublishResponse */ { UA_TYPENAME("RepublishResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {833}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {833LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {835LU}}, /* .binaryEncodingId */ sizeof(UA_RepublishResponse), /* .memSize */ - UA_TYPES_REPUBLISHRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 835, /* .binaryEncodingId */ - RepublishResponse_members /* .members */ + RepublishResponse_members /* .members */ +}, +/* TransferResult */ +{ + UA_TYPENAME("TransferResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {836LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {838LU}}, /* .binaryEncodingId */ + sizeof(UA_TransferResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + TransferResult_members /* .members */ +}, +/* TransferSubscriptionsRequest */ +{ + UA_TYPENAME("TransferSubscriptionsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {839LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {841LU}}, /* .binaryEncodingId */ + sizeof(UA_TransferSubscriptionsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + TransferSubscriptionsRequest_members /* .members */ +}, +/* TransferSubscriptionsResponse */ +{ + UA_TYPENAME("TransferSubscriptionsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {842LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {844LU}}, /* .binaryEncodingId */ + sizeof(UA_TransferSubscriptionsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + TransferSubscriptionsResponse_members /* .members */ }, /* DeleteSubscriptionsRequest */ { UA_TYPENAME("DeleteSubscriptionsRequest") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {845}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {845LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {847LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteSubscriptionsRequest), /* .memSize */ - UA_TYPES_DELETESUBSCRIPTIONSREQUEST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 847, /* .binaryEncodingId */ - DeleteSubscriptionsRequest_members /* .members */ + DeleteSubscriptionsRequest_members /* .members */ }, /* DeleteSubscriptionsResponse */ { UA_TYPENAME("DeleteSubscriptionsResponse") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {848}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {848LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {850LU}}, /* .binaryEncodingId */ sizeof(UA_DeleteSubscriptionsResponse), /* .memSize */ - UA_TYPES_DELETESUBSCRIPTIONSRESPONSE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 850, /* .binaryEncodingId */ - DeleteSubscriptionsResponse_members /* .members */ + DeleteSubscriptionsResponse_members /* .members */ }, /* BuildInfo */ { UA_TYPENAME("BuildInfo") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {338}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {338LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {340LU}}, /* .binaryEncodingId */ sizeof(UA_BuildInfo), /* .memSize */ - UA_TYPES_BUILDINFO, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 340, /* .binaryEncodingId */ - BuildInfo_members /* .members */ + BuildInfo_members /* .members */ }, /* RedundancySupport */ { UA_TYPENAME("RedundancySupport") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {851}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {851LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_RedundancySupport), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - RedundancySupport_members /* .members */ + RedundancySupport_members /* .members */ }, /* ServerState */ { UA_TYPENAME("ServerState") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {852}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {852LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_ServerState), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - ServerState_members /* .members */ + ServerState_members /* .members */ }, /* ServerDiagnosticsSummaryDataType */ { UA_TYPENAME("ServerDiagnosticsSummaryDataType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {859}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {859LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {861LU}}, /* .binaryEncodingId */ sizeof(UA_ServerDiagnosticsSummaryDataType), /* .memSize */ - UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 12, /* .membersSize */ - 861, /* .binaryEncodingId */ - ServerDiagnosticsSummaryDataType_members /* .members */ + ServerDiagnosticsSummaryDataType_members /* .members */ }, /* ServerStatusDataType */ { UA_TYPENAME("ServerStatusDataType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {862}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {862LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {864LU}}, /* .binaryEncodingId */ sizeof(UA_ServerStatusDataType), /* .memSize */ - UA_TYPES_SERVERSTATUSDATATYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 864, /* .binaryEncodingId */ - ServerStatusDataType_members /* .members */ + ServerStatusDataType_members /* .members */ }, /* Range */ { UA_TYPENAME("Range") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {884}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {884LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {886LU}}, /* .binaryEncodingId */ sizeof(UA_Range), /* .memSize */ - UA_TYPES_RANGE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 886, /* .binaryEncodingId */ - Range_members /* .members */ + Range_members /* .members */ }, /* EUInformation */ { UA_TYPENAME("EUInformation") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {887}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {887LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {889LU}}, /* .binaryEncodingId */ sizeof(UA_EUInformation), /* .memSize */ - UA_TYPES_EUINFORMATION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 889, /* .binaryEncodingId */ - EUInformation_members /* .members */ + EUInformation_members /* .members */ }, /* AxisScaleEnumeration */ { UA_TYPENAME("AxisScaleEnumeration") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {12077}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12077LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_AxisScaleEnumeration), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - AxisScaleEnumeration_members /* .members */ + AxisScaleEnumeration_members /* .members */ }, /* ComplexNumberType */ { UA_TYPENAME("ComplexNumberType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {12171}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12171LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12181LU}}, /* .binaryEncodingId */ sizeof(UA_ComplexNumberType), /* .memSize */ - UA_TYPES_COMPLEXNUMBERTYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 12181, /* .binaryEncodingId */ - ComplexNumberType_members /* .members */ + ComplexNumberType_members /* .members */ }, /* DoubleComplexNumberType */ { UA_TYPENAME("DoubleComplexNumberType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {12172}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12172LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12182LU}}, /* .binaryEncodingId */ sizeof(UA_DoubleComplexNumberType), /* .memSize */ - UA_TYPES_DOUBLECOMPLEXNUMBERTYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 12182, /* .binaryEncodingId */ - DoubleComplexNumberType_members /* .members */ + DoubleComplexNumberType_members /* .members */ }, /* AxisInformation */ { UA_TYPENAME("AxisInformation") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {12079}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12079LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12089LU}}, /* .binaryEncodingId */ sizeof(UA_AxisInformation), /* .memSize */ - UA_TYPES_AXISINFORMATION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 12089, /* .binaryEncodingId */ - AxisInformation_members /* .members */ + AxisInformation_members /* .members */ }, /* XVType */ { UA_TYPENAME("XVType") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {12080}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12080LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12090LU}}, /* .binaryEncodingId */ sizeof(UA_XVType), /* .memSize */ - UA_TYPES_XVTYPE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 12090, /* .binaryEncodingId */ - XVType_members /* .members */ + XVType_members /* .members */ }, /* EnumDefinition */ { UA_TYPENAME("EnumDefinition") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {100}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {100LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {123LU}}, /* .binaryEncodingId */ sizeof(UA_EnumDefinition), /* .memSize */ - UA_TYPES_ENUMDEFINITION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 123, /* .binaryEncodingId */ - EnumDefinition_members /* .members */ + EnumDefinition_members /* .members */ }, /* ReadEventDetails */ { UA_TYPENAME("ReadEventDetails") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {644}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {644LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {646LU}}, /* .binaryEncodingId */ sizeof(UA_ReadEventDetails), /* .memSize */ - UA_TYPES_READEVENTDETAILS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 4, /* .membersSize */ - 646, /* .binaryEncodingId */ - ReadEventDetails_members /* .members */ + ReadEventDetails_members /* .members */ }, /* ReadProcessedDetails */ { UA_TYPENAME("ReadProcessedDetails") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {650}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {650LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {652LU}}, /* .binaryEncodingId */ sizeof(UA_ReadProcessedDetails), /* .memSize */ - UA_TYPES_READPROCESSEDDETAILS, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 652, /* .binaryEncodingId */ - ReadProcessedDetails_members /* .members */ + ReadProcessedDetails_members /* .members */ }, /* ModificationInfo */ { UA_TYPENAME("ModificationInfo") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {11216}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11216LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11226LU}}, /* .binaryEncodingId */ sizeof(UA_ModificationInfo), /* .memSize */ - UA_TYPES_MODIFICATIONINFO, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 11226, /* .binaryEncodingId */ - ModificationInfo_members /* .members */ + ModificationInfo_members /* .members */ }, /* HistoryModifiedData */ { UA_TYPENAME("HistoryModifiedData") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {11217}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11217LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {11227LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryModifiedData), /* .memSize */ - UA_TYPES_HISTORYMODIFIEDDATA, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 11227, /* .binaryEncodingId */ - HistoryModifiedData_members /* .members */ + HistoryModifiedData_members /* .members */ }, /* HistoryEvent */ { UA_TYPENAME("HistoryEvent") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {659}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {659LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {661LU}}, /* .binaryEncodingId */ sizeof(UA_HistoryEvent), /* .memSize */ - UA_TYPES_HISTORYEVENT, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 661, /* .binaryEncodingId */ - HistoryEvent_members /* .members */ + HistoryEvent_members /* .members */ }, /* DataChangeNotification */ { UA_TYPENAME("DataChangeNotification") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {809}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {809LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {811LU}}, /* .binaryEncodingId */ sizeof(UA_DataChangeNotification), /* .memSize */ - UA_TYPES_DATACHANGENOTIFICATION, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 811, /* .binaryEncodingId */ - DataChangeNotification_members /* .members */ + DataChangeNotification_members /* .members */ }, /* EventNotificationList */ { UA_TYPENAME("EventNotificationList") /* .typeName */ - {0, UA_NODEIDTYPE_NUMERIC, {914}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {914LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {916LU}}, /* .binaryEncodingId */ sizeof(UA_EventNotificationList), /* .memSize */ - UA_TYPES_EVENTNOTIFICATIONLIST, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 1, /* .membersSize */ - 916, /* .binaryEncodingId */ - EventNotificationList_members /* .members */ + EventNotificationList_members /* .members */ }, }; -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/transport_generated.c" ***********************************/ +/**** amalgamated original file "/build/src_generated/open62541/transport_generated.c" ****/ -/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_datatypes.py - * on host mintaka by user pdie at 2021-06-21 11:34:37 */ +/********************************** + * Autogenerated -- do not modify * + **********************************/ /* MessageType */ @@ -18940,293 +17374,264 @@ const UA_DataType UA_TYPES[UA_TYPES_COUNT] = { static UA_DataTypeMember TcpMessageHeader_members[2] = { { UA_TYPENAME("MessageTypeAndChunkType") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MessageSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpMessageHeader, messageSize) - offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* TcpHelloMessage */ static UA_DataTypeMember TcpHelloMessage_members[6] = { { UA_TYPENAME("ProtocolVersion") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReceiveBufferSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpHelloMessage, receiveBufferSize) - offsetof(UA_TcpHelloMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SendBufferSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpHelloMessage, sendBufferSize) - offsetof(UA_TcpHelloMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxMessageSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpHelloMessage, maxMessageSize) - offsetof(UA_TcpHelloMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxChunkCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpHelloMessage, maxChunkCount) - offsetof(UA_TcpHelloMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("EndpointUrl") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_TcpHelloMessage, endpointUrl) - offsetof(UA_TcpHelloMessage, maxChunkCount) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* TcpAcknowledgeMessage */ static UA_DataTypeMember TcpAcknowledgeMessage_members[5] = { { UA_TYPENAME("ProtocolVersion") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReceiveBufferSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - offsetof(UA_TcpAcknowledgeMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SendBufferSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxMessageSize") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("MaxChunkCount") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_TcpAcknowledgeMessage, maxChunkCount) - offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* TcpErrorMessage */ static UA_DataTypeMember TcpErrorMessage_members[2] = { { UA_TYPENAME("Error") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("Reason") /* .memberName */ - UA_TYPES_STRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ offsetof(UA_TcpErrorMessage, reason) - offsetof(UA_TcpErrorMessage, error) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* AsymmetricAlgorithmSecurityHeader */ static UA_DataTypeMember AsymmetricAlgorithmSecurityHeader_members[3] = { { UA_TYPENAME("SecurityPolicyUri") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("SenderCertificate") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, securityPolicyUri) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("ReceiverCertificateThumbprint") /* .memberName */ - UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ offsetof(UA_AsymmetricAlgorithmSecurityHeader, receiverCertificateThumbprint) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - sizeof(UA_ByteString), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; /* SequenceHeader */ static UA_DataTypeMember SequenceHeader_members[2] = { { UA_TYPENAME("SequenceNumber") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ 0, /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ }, { UA_TYPENAME("RequestId") /* .memberName */ - UA_TYPES_UINT32, /* .memberTypeIndex */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ offsetof(UA_SequenceHeader, requestId) - offsetof(UA_SequenceHeader, sequenceNumber) - sizeof(UA_UInt32), /* .padding */ - true, /* .namespaceZero */ false, /* .isArray */ - false /* .isOptional */ + false /* .isOptional */ },}; const UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT] = { /* MessageType */ { UA_TYPENAME("MessageType") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_MessageType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - MessageType_members /* .members */ + MessageType_members /* .members */ }, /* ChunkType */ { UA_TYPENAME("ChunkType") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_ChunkType), /* .memSize */ - UA_TYPES_INT32, /* .typeIndex */ UA_DATATYPEKIND_ENUM, /* .typeKind */ true, /* .pointerFree */ UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ 0, /* .membersSize */ - 0, /* .binaryEncodingId */ - ChunkType_members /* .members */ + ChunkType_members /* .members */ }, /* TcpMessageHeader */ { UA_TYPENAME("TcpMessageHeader") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_TcpMessageHeader), /* .memSize */ - UA_TRANSPORT_TCPMESSAGEHEADER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 0, /* .binaryEncodingId */ - TcpMessageHeader_members /* .members */ + TcpMessageHeader_members /* .members */ }, /* TcpHelloMessage */ { UA_TYPENAME("TcpHelloMessage") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_TcpHelloMessage), /* .memSize */ - UA_TRANSPORT_TCPHELLOMESSAGE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 6, /* .membersSize */ - 0, /* .binaryEncodingId */ - TcpHelloMessage_members /* .members */ + TcpHelloMessage_members /* .members */ }, /* TcpAcknowledgeMessage */ { UA_TYPENAME("TcpAcknowledgeMessage") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_TcpAcknowledgeMessage), /* .memSize */ - UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 5, /* .membersSize */ - 0, /* .binaryEncodingId */ - TcpAcknowledgeMessage_members /* .members */ + TcpAcknowledgeMessage_members /* .members */ }, /* TcpErrorMessage */ { UA_TYPENAME("TcpErrorMessage") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_TcpErrorMessage), /* .memSize */ - UA_TRANSPORT_TCPERRORMESSAGE, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 0, /* .binaryEncodingId */ - TcpErrorMessage_members /* .members */ + TcpErrorMessage_members /* .members */ }, /* AsymmetricAlgorithmSecurityHeader */ { UA_TYPENAME("AsymmetricAlgorithmSecurityHeader") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_AsymmetricAlgorithmSecurityHeader), /* .memSize */ - UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ false, /* .pointerFree */ false, /* .overlayable */ 3, /* .membersSize */ - 0, /* .binaryEncodingId */ - AsymmetricAlgorithmSecurityHeader_members /* .members */ + AsymmetricAlgorithmSecurityHeader_members /* .members */ }, /* SequenceHeader */ { UA_TYPENAME("SequenceHeader") /* .typeName */ {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ sizeof(UA_SequenceHeader), /* .memSize */ - UA_TRANSPORT_SEQUENCEHEADER, /* .typeIndex */ UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ true, /* .pointerFree */ false, /* .overlayable */ 2, /* .membersSize */ - 0, /* .binaryEncodingId */ - SequenceHeader_members /* .members */ + SequenceHeader_members /* .members */ }, }; -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/statuscodes.c" ***********************************/ +/**** amalgamated original file "/build/src_generated/open62541/statuscodes.c" ****/ -/********************************************************** - * Autogenerated -- do not modify - * Generated from /home/pdie/sonstiges/qtopcua/repos/open62541/tools/schema/StatusCode.csv with script /home/pdie/sonstiges/qtopcua/repos/open62541/tools/generate_statuscode_descriptions.py - *********************************************************/ +/********************************** + * Autogenerated -- do not modify * + **********************************/ typedef struct { @@ -19240,9 +17645,12 @@ const char * UA_StatusCode_name(UA_StatusCode code) { return emptyStatusCodeName; } #else -static const size_t statusCodeDescriptionsSize = 237; -static const UA_StatusCodeName statusCodeDescriptions[237] = { +static const size_t statusCodeDescriptionsSize = 252; +static const UA_StatusCodeName statusCodeDescriptions[252] = { + {UA_STATUSCODE_GOOD, "Good"}, {UA_STATUSCODE_GOOD, "Good"}, + {UA_STATUSCODE_UNCERTAIN, "Uncertain"}, + {UA_STATUSCODE_BAD, "Bad"}, {UA_STATUSCODE_BADUNEXPECTEDERROR, "BadUnexpectedError"}, {UA_STATUSCODE_BADINTERNALERROR, "BadInternalError"}, {UA_STATUSCODE_BADOUTOFMEMORY, "BadOutOfMemory"}, @@ -19390,6 +17798,7 @@ static const UA_StatusCodeName statusCodeDescriptions[237] = { {UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS, "BadTooManyPublishRequests"}, {UA_STATUSCODE_BADNOSUBSCRIPTION, "BadNoSubscription"}, {UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN, "BadSequenceNumberUnknown"}, + {UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED, "GoodRetransmissionQueueNotSupported"}, {UA_STATUSCODE_BADMESSAGENOTAVAILABLE, "BadMessageNotAvailable"}, {UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE, "BadInsufficientClientProfile"}, {UA_STATUSCODE_BADSTATENOTACTIVE, "BadStateNotActive"}, @@ -19454,6 +17863,8 @@ static const UA_StatusCodeName statusCodeDescriptions[237] = { {UA_STATUSCODE_GOODDATAIGNORED, "GoodDataIgnored"}, {UA_STATUSCODE_BADREQUESTNOTALLOWED, "BadRequestNotAllowed"}, {UA_STATUSCODE_BADREQUESTNOTCOMPLETE, "BadRequestNotComplete"}, + {UA_STATUSCODE_BADTICKETREQUIRED, "BadTicketRequired"}, + {UA_STATUSCODE_BADTICKETINVALID, "BadTicketInvalid"}, {UA_STATUSCODE_GOODEDITED, "GoodEdited"}, {UA_STATUSCODE_GOODPOSTACTIONFAILED, "GoodPostActionFailed"}, {UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED, "UncertainDominantValueChanged"}, @@ -19461,6 +17872,15 @@ static const UA_StatusCodeName statusCodeDescriptions[237] = { {UA_STATUSCODE_BADDOMINANTVALUECHANGED, "BadDominantValueChanged"}, {UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED, "UncertainDependentValueChanged"}, {UA_STATUSCODE_BADDEPENDENTVALUECHANGED, "BadDependentValueChanged"}, + {UA_STATUSCODE_GOODEDITED_DEPENDENTVALUECHANGED, "GoodEdited_DependentValueChanged"}, + {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED, "GoodEdited_DominantValueChanged"}, + {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "GoodEdited_DominantValueChanged_DependentValueChanged"}, + {UA_STATUSCODE_BADEDITED_OUTOFRANGE, "BadEdited_OutOfRange"}, + {UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE, "BadInitialValue_OutOfRange"}, + {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED, "BadOutOfRange_DominantValueChanged"}, + {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged"}, + {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadOutOfRange_DominantValueChanged_DependentValueChanged"}, + {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged_DependentValueChanged"}, {UA_STATUSCODE_GOODCOMMUNICATIONEVENT, "GoodCommunicationEvent"}, {UA_STATUSCODE_GOODSHUTDOWNEVENT, "GoodShutdownEvent"}, {UA_STATUSCODE_GOODCALLAGAIN, "GoodCallAgain"}, @@ -19483,7 +17903,7 @@ static const UA_StatusCodeName statusCodeDescriptions[237] = { const char * UA_StatusCode_name(UA_StatusCode code) { for (size_t i = 0; i < statusCodeDescriptionsSize; ++i) { - if (statusCodeDescriptions[i].code == code) + if (UA_StatusCode_isEqualTop(statusCodeDescriptions[i].code,code)) return statusCodeDescriptions[i].name; } return statusCodeDescriptions[statusCodeDescriptionsSize-1].name; @@ -19491,7 +17911,7 @@ const char * UA_StatusCode_name(UA_StatusCode code) { #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_util.c" ***********************************/ +/**** amalgamated original file "/src/ua_util.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -19504,7 +17924,6 @@ const char * UA_StatusCode_name(UA_StatusCode code) { - size_t UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, UA_UInt32 *number, UA_Byte base) { UA_assert(buf); @@ -19536,6 +17955,8 @@ UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number) { UA_StatusCode UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, u16 *outPort, UA_String *outPath) { + UA_Boolean ipv6 = false; + /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */ if(endpointUrl->length < 11) { return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; @@ -19562,6 +17983,7 @@ UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, if(curr == endpointUrl->length) return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; curr++; + ipv6 = true; } else { /* IPv4 or hostname: opc.tcp://something.something:1234/path */ for(; curr < endpointUrl->length; ++curr) { @@ -19571,8 +17993,19 @@ UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, } /* Set the hostname */ - outHostname->data = &endpointUrl->data[10]; - outHostname->length = curr - 10; + if(ipv6) { + /* Skip the ipv6 '[]' container for getaddrinfo() later */ + outHostname->data = &endpointUrl->data[11]; + outHostname->length = curr - 12; + } else { + outHostname->data = &endpointUrl->data[10]; + outHostname->length = curr - 10; + } + + /* Empty string? */ + if(outHostname->length == 0) + outHostname->data = NULL; + if(curr == endpointUrl->length) return UA_STATUSCODE_GOOD; @@ -19581,7 +18014,8 @@ UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, if(++curr == endpointUrl->length) return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; u32 largeNum; - size_t progress = UA_readNumber(&endpointUrl->data[curr], endpointUrl->length - curr, &largeNum); + size_t progress = UA_readNumber(&endpointUrl->data[curr], + endpointUrl->length - curr, &largeNum); if(progress == 0 || largeNum > 65535) return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; /* Test if the end of a valid port was reached */ @@ -19605,6 +18039,10 @@ UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, if(endpointUrl->data[endpointUrl->length - 1] == '/') outPath->length--; + /* Empty string? */ + if(outPath->length == 0) + outPath->data = NULL; + return UA_STATUSCODE_GOOD; } @@ -19698,427 +18136,205 @@ UA_ByteString_fromBase64(UA_ByteString *bs, return UA_STATUSCODE_GOOD; } +/* Key Value Map */ + UA_StatusCode -UA_NodeId_print(const UA_NodeId *id, UA_String *output) { - UA_String_clear(output); - if(!id) +UA_KeyValueMap_setQualified(UA_KeyValuePair **map, size_t *mapSize, + const UA_QualifiedName *key, + const UA_Variant *value) { + /* Parameter exists already */ + const UA_Variant *v = UA_KeyValueMap_getQualified(*map, *mapSize, key); + if(v) { + UA_Variant copyV; + UA_StatusCode res = UA_Variant_copy(v, ©V); + if(res != UA_STATUSCODE_GOOD) + return res; + UA_Variant *target = (UA_Variant*)(uintptr_t)v; + UA_Variant_clear(target); + *target = copyV; return UA_STATUSCODE_GOOD; - - char *nsStr = NULL; - long snprintfLen = 0; - size_t nsLen = 0; - if(id->namespaceIndex != 0) { - nsStr = (char*)UA_malloc(9+1); // strlen("ns=XXXXX;") = 9 + Nullbyte - snprintfLen = UA_snprintf(nsStr, 10, "ns=%d;", id->namespaceIndex); - if(snprintfLen < 0 || snprintfLen >= 10) { - UA_free(nsStr); - return UA_STATUSCODE_BADINTERNALERROR; - } - nsLen = (size_t)(snprintfLen); - } - - UA_ByteString byteStr = UA_BYTESTRING_NULL; - switch (id->identifierType) { - case UA_NODEIDTYPE_NUMERIC: - /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 - * chars, delim = 1 , nullbyte = 1-> 17 chars */ - output->length = nsLen + 2 + 10 + 1; - output->data = (UA_Byte*)UA_malloc(output->length); - if(output->data == NULL) { - output->length = 0; - UA_free(nsStr); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - snprintfLen = UA_snprintf((char*)output->data, output->length, "%si=%lu", - nsLen > 0 ? nsStr : "", - (unsigned long )id->identifier.numeric); - break; - case UA_NODEIDTYPE_STRING: - /* ns (16bit) = 5 chars, strlen + nullbyte */ - output->length = nsLen + 2 + id->identifier.string.length + 1; - output->data = (UA_Byte*)UA_malloc(output->length); - if(output->data == NULL) { - output->length = 0; - UA_free(nsStr); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - snprintfLen = UA_snprintf((char*)output->data, output->length, "%ss=%.*s", - nsLen > 0 ? nsStr : "", (int)id->identifier.string.length, - id->identifier.string.data); - break; - case UA_NODEIDTYPE_GUID: - /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */ - output->length = nsLen + 2 + 36 + 1; - output->data = (UA_Byte*)UA_malloc(output->length); - if(output->data == NULL) { - output->length = 0; - UA_free(nsStr); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - snprintfLen = UA_snprintf((char*)output->data, output->length, - "%sg=" UA_PRINTF_GUID_FORMAT, nsLen > 0 ? nsStr : "", - UA_PRINTF_GUID_DATA(id->identifier.guid)); - break; - case UA_NODEIDTYPE_BYTESTRING: - UA_ByteString_toBase64(&id->identifier.byteString, &byteStr); - /* ns (16bit) = 5 chars + LEN + nullbyte */ - output->length = nsLen + 2 + byteStr.length + 1; - output->data = (UA_Byte*)UA_malloc(output->length); - if(output->data == NULL) { - output->length = 0; - UA_String_deleteMembers(&byteStr); - UA_free(nsStr); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - snprintfLen = UA_snprintf((char*)output->data, output->length, "%sb=%.*s", - nsLen > 0 ? nsStr : "", - (int)byteStr.length, byteStr.data); - UA_String_deleteMembers(&byteStr); - break; - } - UA_free(nsStr); - - if(snprintfLen < 0 || snprintfLen >= (long) output->length) { - UA_free(output->data); - output->data = NULL; - output->length = 0; - return UA_STATUSCODE_BADINTERNALERROR; } - output->length = (size_t)snprintfLen; - - return UA_STATUSCODE_GOOD; -} - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_workqueue.c" ***********************************/ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2014-2016 (c) Sten Grüner - * Copyright 2015 (c) Chris Iatrou - * Copyright 2015 (c) Nick Goossens - * Copyright 2015 (c) Jörg Schüler-Maroldt - * Copyright 2015-2016 (c) Oleksiy Vasylyev - * Copyright 2016-2017 (c) Florian Palm - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH - * Copyright 2016 (c) Lorenz Haas - * Copyright 2017 (c) Jonas Green - */ - -void UA_WorkQueue_init(UA_WorkQueue *wq) { - /* Initialized the linked list for delayed callbacks */ - SIMPLEQ_INIT(&wq->delayedCallbacks); - -#if UA_MULTITHREADING >= 200 - wq->delayedCallbacks_checkpoint = NULL; - UA_LOCK_INIT(wq->delayedCallbacks_accessMutex) - - /* Initialize the dispatch queue for worker threads */ - SIMPLEQ_INIT(&wq->dispatchQueue); - UA_LOCK_INIT(wq->dispatchQueue_accessMutex) - pthread_cond_init(&wq->dispatchQueue_condition, NULL); - UA_LOCK_INIT(wq->dispatchQueue_conditionMutex) -#endif + /* Append to the array */ + UA_KeyValuePair pair; + pair.key = *key; + pair.value = *value; + return UA_Array_appendCopy((void**)map, mapSize, &pair, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); } -#if UA_MULTITHREADING >= 200 -/* Forward declaration */ -static void UA_WorkQueue_manuallyProcessDelayed(UA_WorkQueue *wq); -#endif - -void UA_WorkQueue_cleanup(UA_WorkQueue *wq) { -#if UA_MULTITHREADING >= 200 - /* Shut down workers */ - UA_WorkQueue_stop(wq); - - /* Execute remaining work in the dispatch queue */ - while(true) { - UA_LOCK(wq->dispatchQueue_accessMutex); - UA_DelayedCallback *dc = SIMPLEQ_FIRST(&wq->dispatchQueue); - if(!dc) { - UA_UNLOCK(wq->dispatchQueue_accessMutex); - break; - } - SIMPLEQ_REMOVE_HEAD(&wq->dispatchQueue, next); - UA_UNLOCK(wq->dispatchQueue_accessMutex); - dc->callback(dc->application, dc->data); - UA_free(dc); - } -#endif - - /* All workers are shut down. Execute remaining delayed work here. */ - UA_WorkQueue_manuallyProcessDelayed(wq); - -#if UA_MULTITHREADING >= 200 - wq->delayedCallbacks_checkpoint = NULL; - UA_LOCK_DESTROY(wq->dispatchQueue_accessMutex); - pthread_cond_destroy(&wq->dispatchQueue_condition); - UA_LOCK_DESTROY(wq->dispatchQueue_conditionMutex); - UA_LOCK_DESTROY(wq->delayedCallbacks_accessMutex); -#endif +UA_StatusCode +UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize, + const char *key, const UA_Variant *value) { + UA_QualifiedName qnKey; + qnKey.namespaceIndex = 0; + qnKey.name = UA_STRING((char*)(uintptr_t)key); + return UA_KeyValueMap_setQualified(map, mapSize, &qnKey, value); } -/***********/ -/* Workers */ -/***********/ - -#if UA_MULTITHREADING >= 200 - -static void * -workerLoop(UA_Worker *worker) { - UA_WorkQueue *wq = worker->queue; - UA_UInt32 *counter = &worker->counter; - volatile UA_Boolean *running = &worker->running; - - /* Initialize the (thread local) random seed with the ram address - * of the worker. Not for security-critical entropy! */ - UA_random_seed((uintptr_t)worker); +const UA_Variant * +UA_KeyValueMap_getQualified(UA_KeyValuePair *map, size_t mapSize, + const UA_QualifiedName *key) { + for(size_t i = 0; i < mapSize; i++) { + if(map[i].key.namespaceIndex == key->namespaceIndex && + UA_String_equal(&map[i].key.name, &key->name)) + return &map[i].value; - while(*running) { - UA_atomic_addUInt32(counter, 1); - - /* Remove a callback from the queue */ - UA_LOCK(wq->dispatchQueue_accessMutex); - UA_DelayedCallback *dc = SIMPLEQ_FIRST(&wq->dispatchQueue); - if(dc) - SIMPLEQ_REMOVE_HEAD(&wq->dispatchQueue, next); - UA_UNLOCK(wq->dispatchQueue_accessMutex); - - /* Nothing to do. Sleep until a callback is dispatched */ - if(!dc) { - UA_LOCK(wq->dispatchQueue_conditionMutex); - pthread_cond_wait(&wq->dispatchQueue_condition, - &wq->dispatchQueue_conditionMutex); - UA_UNLOCK(wq->dispatchQueue_conditionMutex); - continue; - } - - /* Execute */ - if(dc->callback) - dc->callback(dc->application, dc->data); - UA_free(dc); } - return NULL; } -/* Can be called repeatedly and starts additional workers */ -UA_StatusCode -UA_WorkQueue_start(UA_WorkQueue *wq, size_t workersCount) { - if(wq->workersSize > 0 || workersCount == 0) - return UA_STATUSCODE_BADINTERNALERROR; - - /* Create the worker array */ - wq->workers = (UA_Worker*)UA_calloc(workersCount, sizeof(UA_Worker)); - if(!wq->workers) - return UA_STATUSCODE_BADOUTOFMEMORY; - wq->workersSize = workersCount; - - /* Spin up the workers */ - for(size_t i = 0; i < workersCount; ++i) { - UA_Worker *w = &wq->workers[i]; - w->queue = wq; - w->counter = 0; - w->running = true; - pthread_create(&w->thread, NULL, (void* (*)(void*))workerLoop, w); - } - return UA_STATUSCODE_GOOD; +const UA_Variant * +UA_KeyValueMap_get(UA_KeyValuePair *map, size_t mapSize, + const char *key) { + UA_QualifiedName qnKey; + qnKey.namespaceIndex = 0; + qnKey.name = UA_STRING((char*)(uintptr_t)key); + return UA_KeyValueMap_getQualified(map, mapSize, &qnKey); } -void UA_WorkQueue_stop(UA_WorkQueue *wq) { - if(wq->workersSize == 0) - return; - - /* Signal the workers to stop */ - for(size_t i = 0; i < wq->workersSize; ++i) - wq->workers[i].running = false; - - /* Wake up all workers */ - pthread_cond_broadcast(&wq->dispatchQueue_condition); - - /* Wait for the workers to finish, then clean up */ - for(size_t i = 0; i < wq->workersSize; ++i) - pthread_join(wq->workers[i].thread, NULL); - - UA_free(wq->workers); - wq->workers = NULL; - wq->workersSize = 0; +/* Returns NULL if the parameter is not defined or not of the right datatype */ +const UA_Variant * +UA_KeyValueMap_getScalar(UA_KeyValuePair *map, size_t mapSize, + const char *key, const UA_DataType *type) { + const UA_Variant *v = UA_KeyValueMap_get(map, mapSize, key); + if(!v || !UA_Variant_hasScalarType(v, type)) + return NULL; + return v; } -void UA_WorkQueue_enqueue(UA_WorkQueue *wq, UA_ApplicationCallback cb, - void *application, void *data) { - UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_malloc(sizeof(UA_DelayedCallback)); - if(!dc) { - cb(application, data); /* Execute immediately if the memory could not be allocated */ - return; - } - - dc->callback = cb; - dc->application = application; - dc->data = data; - - /* Enqueue for the worker threads */ - UA_LOCK(wq->dispatchQueue_accessMutex); - SIMPLEQ_INSERT_TAIL(&wq->dispatchQueue, dc, next); - UA_UNLOCK(wq->dispatchQueue_accessMutex); - - /* Wake up sleeping workers */ - pthread_cond_broadcast(&wq->dispatchQueue_condition); +const UA_Variant * +UA_KeyValueMap_getArray(UA_KeyValuePair *map, size_t mapSize, + const char *key, const UA_DataType *type) { + const UA_Variant *v = UA_KeyValueMap_get(map, mapSize, key); + if(!v || !UA_Variant_hasArrayType(v, type)) + return NULL; + return v; } -#endif - -/*********************/ -/* Delayed Callbacks */ -/*********************/ - -#if UA_MULTITHREADING >= 200 - -/* Delayed Callbacks are called only when all callbacks that were dispatched - * prior are finished. After every UA_MAX_DELAYED_SAMPLE delayed Callbacks that - * were added to the queue, we sample the counters from the workers. The - * counters are compared to the last counters that were sampled. If every worker - * has proceeded the counter, then we know that all delayed callbacks prior to - * the last sample-point are safe to execute. */ - -/* Sample the worker counter for every nth delayed callback. This is used to - * test that all workers have **finished** their current job before the delayed - * callback is processed. */ -#define UA_MAX_DELAYED_SAMPLE 100 +void +UA_KeyValueMap_deleteQualified(UA_KeyValuePair **map, size_t *mapSize, + const UA_QualifiedName *key) { + UA_KeyValuePair *m = *map; + size_t s = *mapSize; + for(size_t i = 0; i < s; i++) { + if(m[i].key.namespaceIndex != key->namespaceIndex || + !UA_String_equal(&m[i].key.name, &key->name)) + continue; -/* Call only with a held mutex for the delayed callbacks */ -static void -dispatchDelayedCallbacks(UA_WorkQueue *wq, UA_DelayedCallback *cb) { - /* Are callbacks before the last checkpoint ready? */ - for(size_t i = 0; i < wq->workersSize; ++i) { - if(wq->workers[i].counter == wq->workers[i].checkpointCounter) - return; - } + /* Clean the pair */ + UA_KeyValuePair_clear(&m[i]); - /* Dispatch all delayed callbacks up to the checkpoint. - * TODO: Move over the entire queue up to the checkpoint in one step. */ - if(wq->delayedCallbacks_checkpoint != NULL) { - UA_DelayedCallback *iter, *tmp_iter; - SIMPLEQ_FOREACH_SAFE(iter, &wq->delayedCallbacks, next, tmp_iter) { - UA_LOCK(wq->dispatchQueue_accessMutex); - SIMPLEQ_INSERT_TAIL(&wq->dispatchQueue, iter, next); - UA_UNLOCK(wq->dispatchQueue_accessMutex); - if(iter == wq->delayedCallbacks_checkpoint) - break; + /* Move the last pair to fill the empty slot */ + if(s > 1 && i < s - 1) { + m[i] = m[s-1]; + UA_KeyValuePair_init(&m[s-1]); } - } - /* Create the new sample point */ - for(size_t i = 0; i < wq->workersSize; ++i) - wq->workers[i].checkpointCounter = wq->workers[i].counter; - wq->delayedCallbacks_checkpoint = cb; -} - -#endif - -void -UA_WorkQueue_enqueueDelayed(UA_WorkQueue *wq, UA_DelayedCallback *cb) { -#if UA_MULTITHREADING >= 200 - UA_LOCK(wq->dispatchQueue_accessMutex); -#endif - - SIMPLEQ_INSERT_HEAD(&wq->delayedCallbacks, cb, next); - -#if UA_MULTITHREADING >= 200 - wq->delayedCallbacks_sinceDispatch++; - if(wq->delayedCallbacks_sinceDispatch > UA_MAX_DELAYED_SAMPLE) { - dispatchDelayedCallbacks(wq, cb); - wq->delayedCallbacks_sinceDispatch = 0; + UA_StatusCode res = UA_Array_resize((void**)map, mapSize, *mapSize-1, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + (void)res; + *mapSize = s - 1; /* In case resize fails, keep the longer original + * array around. Resize never fails when reducing + * the size to zero. Reduce the size integer in + * any case. */ + return; } - - UA_UNLOCK(wq->dispatchQueue_accessMutex); -#endif } -/* Assumes all workers are shut down */ -void UA_WorkQueue_manuallyProcessDelayed(UA_WorkQueue *wq) { - UA_DelayedCallback *dc, *dc_tmp; - SIMPLEQ_FOREACH_SAFE(dc, &wq->delayedCallbacks, next, dc_tmp) { - SIMPLEQ_REMOVE_HEAD(&wq->delayedCallbacks, next); - if(dc->callback) - dc->callback(dc->application, dc->data); - UA_free(dc); - } -#if UA_MULTITHREADING >= 200 - wq->delayedCallbacks_checkpoint = NULL; -#endif +void +UA_KeyValueMap_delete(UA_KeyValuePair **map, size_t *mapSize, + const char *key) { + UA_QualifiedName qnKey; + qnKey.namespaceIndex = 0; + qnKey.name = UA_STRING((char*)(uintptr_t)key); + UA_KeyValueMap_deleteQualified(map, mapSize, &qnKey); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_timer.c" ***********************************/ +/**** amalgamated original file "/src/ua_timer.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2017, 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2017 (c) Stefan Profanter, fortiss GmbH */ -struct UA_TimerEntry { - ZIP_ENTRY(UA_TimerEntry) zipfields; - UA_DateTime nextTime; /* The next time when the callback - * is to be executed */ - UA_UInt64 interval; /* Interval in 100ns resolution */ - UA_Boolean repeated; /* Repeated callback? */ - - UA_ApplicationCallback callback; - void *application; - void *data; - - ZIP_ENTRY(UA_TimerEntry) idZipfields; - UA_UInt64 id; /* Id of the entry */ -}; - /* There may be several entries with the same nextTime in the tree. We give them * an absolute order by considering the memory address to break ties. Because of * this, the nextTime property cannot be used to lookup specific entries. */ -static enum ZIP_CMP +static enum aa_cmp cmpDateTime(const UA_DateTime *a, const UA_DateTime *b) { if(*a < *b) - return ZIP_CMP_LESS; + return AA_CMP_LESS; if(*a > *b) - return ZIP_CMP_MORE; + return AA_CMP_MORE; if(a == b) - return ZIP_CMP_EQ; + return AA_CMP_EQ; if(a < b) - return ZIP_CMP_LESS; - return ZIP_CMP_MORE; + return AA_CMP_LESS; + return AA_CMP_MORE; } -ZIP_PROTTYPE(UA_TimerZip, UA_TimerEntry, UA_DateTime) -ZIP_IMPL(UA_TimerZip, UA_TimerEntry, zipfields, UA_DateTime, nextTime, cmpDateTime) - /* The identifiers of entries are unique */ -static enum ZIP_CMP +static enum aa_cmp cmpId(const UA_UInt64 *a, const UA_UInt64 *b) { if(*a < *b) - return ZIP_CMP_LESS; + return AA_CMP_LESS; if(*a == *b) - return ZIP_CMP_EQ; - return ZIP_CMP_MORE; + return AA_CMP_EQ; + return AA_CMP_MORE; } -ZIP_PROTTYPE(UA_TimerIdZip, UA_TimerEntry, UA_UInt64) -ZIP_IMPL(UA_TimerIdZip, UA_TimerEntry, idZipfields, UA_UInt64, id, cmpId) +static UA_DateTime +calculateNextTime(UA_DateTime currentTime, UA_DateTime baseTime, + UA_DateTime interval) { + /* Take the difference between current and base time */ + UA_DateTime diffCurrentTimeBaseTime = currentTime - baseTime; + + /* Take modulo of the diff time with the interval. This is the duration we + * are already "into" the current interval. Subtract it from (current + + * interval) to get the next execution time. */ + UA_DateTime cycleDelay = diffCurrentTimeBaseTime % interval; + + /* Handle the special case where the baseTime is in the future */ + if(UA_UNLIKELY(cycleDelay < 0)) + cycleDelay += interval; + + return currentTime + interval - cycleDelay; +} void UA_Timer_init(UA_Timer *t) { memset(t, 0, sizeof(UA_Timer)); + aa_init(&t->root, + (enum aa_cmp (*)(const void*, const void*))cmpDateTime, + offsetof(UA_TimerEntry, treeEntry), + offsetof(UA_TimerEntry, nextTime)); + aa_init(&t->idRoot, + (enum aa_cmp (*)(const void*, const void*))cmpId, + offsetof(UA_TimerEntry, idTreeEntry), + offsetof(UA_TimerEntry, id)); + UA_LOCK_INIT(&t->timerMutex); +} + +void +UA_Timer_addTimerEntry(UA_Timer *t, UA_TimerEntry *te, UA_UInt64 *callbackId) { + UA_LOCK(&t->timerMutex); + te->id = ++t->idCounter; + if(callbackId) + *callbackId = te->id; + aa_insert(&t->root, te); + aa_insert(&t->idRoot, te); + UA_UNLOCK(&t->timerMutex); } static UA_StatusCode -addCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, void *data, - UA_DateTime nextTime, UA_UInt64 interval, UA_Boolean repeated, - UA_UInt64 *callbackId) { +addCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, + void *data, UA_DateTime nextTime, UA_UInt64 interval, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) { /* A callback method needs to be present */ if(!callback) return UA_STATUSCODE_BADINTERNALERROR; @@ -20134,15 +18350,15 @@ addCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, voi te->callback = callback; te->application = application; te->data = data; - te->repeated = repeated; te->nextTime = nextTime; + te->timerPolicy = timerPolicy; /* Set the output identifier */ if(callbackId) *callbackId = te->id; - ZIP_INSERT(UA_TimerZip, &t->root, te, ZIP_FFS32(UA_UInt32_random())); - ZIP_INSERT(UA_TimerIdZip, &t->idRoot, te, ZIP_RANK(te, zipfields)); + aa_insert(&t->root, te); + aa_insert(&t->idRoot, te); return UA_STATUSCODE_GOOD; } @@ -20150,7 +18366,12 @@ UA_StatusCode UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, void *data, UA_DateTime date, UA_UInt64 *callbackId) { - return addCallback(t, callback, application, data, date, 0, false, callbackId); + UA_LOCK(&t->timerMutex); + UA_StatusCode res = addCallback(t, callback, application, data, date, + 0, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, + callbackId); + UA_UNLOCK(&t->timerMutex); + return res; } /* Adding repeated callbacks: Add an entry with the "nextTime" timestamp in the @@ -20159,97 +18380,174 @@ UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback, UA_StatusCode UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, void *data, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) { /* The interval needs to be positive */ if(interval_ms <= 0.0) return UA_STATUSCODE_BADINTERNALERROR; - UA_UInt64 interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); - UA_DateTime nextTime = UA_DateTime_nowMonotonic() + (UA_DateTime)interval; - return addCallback(t, callback, application, data, nextTime, - interval, true, callbackId); + if(interval == 0) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Compute the first time for execution */ + UA_DateTime currentTime = UA_DateTime_nowMonotonic(); + UA_DateTime nextTime; + if(baseTime == NULL) { + /* Use "now" as the basetime */ + nextTime = currentTime + (UA_DateTime)interval; + } else { + nextTime = calculateNextTime(currentTime, *baseTime, (UA_DateTime)interval); + } + + UA_LOCK(&t->timerMutex); + UA_StatusCode res = addCallback(t, callback, application, data, nextTime, + interval, timerPolicy, callbackId); + UA_UNLOCK(&t->timerMutex); + return res; } UA_StatusCode -UA_Timer_changeRepeatedCallbackInterval(UA_Timer *t, UA_UInt64 callbackId, - UA_Double interval_ms) { +UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy) { /* The interval needs to be positive */ if(interval_ms <= 0.0) return UA_STATUSCODE_BADINTERNALERROR; + UA_UInt64 interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); + if(interval == 0) + return UA_STATUSCODE_BADINTERNALERROR; - /* Remove from the sorted list */ - UA_TimerEntry *te = ZIP_FIND(UA_TimerIdZip, &t->idRoot, &callbackId); - if(!te) + UA_LOCK(&t->timerMutex); + + /* Remove from the sorted tree */ + UA_TimerEntry *te = (UA_TimerEntry*)aa_find(&t->idRoot, &callbackId); + if(!te) { + UA_UNLOCK(&t->timerMutex); return UA_STATUSCODE_BADNOTFOUND; + } + aa_remove(&t->root, te); - /* Set the repeated callback */ - ZIP_REMOVE(UA_TimerZip, &t->root, te); - te->interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); /* in 100ns resolution */ - te->nextTime = UA_DateTime_nowMonotonic() + (UA_DateTime)te->interval; - ZIP_INSERT(UA_TimerZip, &t->root, te, ZIP_RANK(te, zipfields)); + /* Compute the next time for execution. The logic is identical to the + * creation of a new repeated callback. */ + UA_DateTime currentTime = UA_DateTime_nowMonotonic(); + if(baseTime == NULL) { + /* Use "now" as the basetime */ + te->nextTime = currentTime + (UA_DateTime)interval; + } else { + te->nextTime = calculateNextTime(currentTime, *baseTime, (UA_DateTime)interval); + } + + /* Update the remaining parameters and re-insert */ + te->interval = interval; + te->timerPolicy = timerPolicy; + aa_insert(&t->root, te); + + UA_UNLOCK(&t->timerMutex); return UA_STATUSCODE_GOOD; } void UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId) { - UA_TimerEntry *te = ZIP_FIND(UA_TimerIdZip, &t->idRoot, &callbackId); - if(!te) - return; - - ZIP_REMOVE(UA_TimerZip, &t->root, te); - ZIP_REMOVE(UA_TimerIdZip, &t->idRoot, te); - UA_free(te); + UA_LOCK(&t->timerMutex); + UA_TimerEntry *te = (UA_TimerEntry*)aa_find(&t->idRoot, &callbackId); + if(UA_LIKELY(te != NULL)) { + aa_remove(&t->root, te); + aa_remove(&t->idRoot, te); + UA_free(te); + } + UA_UNLOCK(&t->timerMutex); } UA_DateTime UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic, UA_TimerExecutionCallback executionCallback, void *executionApplication) { + UA_LOCK(&t->timerMutex); UA_TimerEntry *first; - while((first = ZIP_MIN(UA_TimerZip, &t->root)) && + while((first = (UA_TimerEntry*)aa_min(&t->root)) && first->nextTime <= nowMonotonic) { - ZIP_REMOVE(UA_TimerZip, &t->root, first); + aa_remove(&t->root, first); /* Reinsert / remove to their new position first. Because the callback * can interact with the zip tree and expects the same entries in the * root and idRoot trees. */ - if(!first->repeated) { - ZIP_REMOVE(UA_TimerIdZip, &t->idRoot, first); - executionCallback(executionApplication, first->callback, - first->application, first->data); + if(first->interval == 0) { + aa_remove(&t->idRoot, first); + if(first->callback) { + UA_UNLOCK(&t->timerMutex); + executionCallback(executionApplication, first->callback, + first->application, first->data); + UA_LOCK(&t->timerMutex); + } UA_free(first); continue; } /* Set the time for the next execution. Prevent an infinite loop by - * forcing the next processing into the next iteration. */ - first->nextTime += (UA_Int64)first->interval; - if(first->nextTime < nowMonotonic) - first->nextTime = nowMonotonic + 1; - ZIP_INSERT(UA_TimerZip, &t->root, first, ZIP_RANK(first, zipfields)); - executionCallback(executionApplication, first->callback, - first->application, first->data); + * forcing the execution time in the next iteration. + * + * If the timer policy is "CurrentTime", then there is at least the + * interval between executions. This is used for Monitoreditems, for + * which the spec says: The sampling interval indicates the fastest rate + * at which the Server should sample its underlying source for data + * changes. (Part 4, 5.12.1.2) */ + first->nextTime += (UA_DateTime)first->interval; + if(first->nextTime < nowMonotonic) { + if(first->timerPolicy == UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME) + first->nextTime = calculateNextTime(nowMonotonic, first->nextTime, + (UA_DateTime)first->interval); + else + first->nextTime = nowMonotonic + (UA_DateTime)first->interval; + } + + aa_insert(&t->root, first); + + if(!first->callback) + continue; + + /* Unlock the mutes before dropping into the callback. So that the timer + * itself can be edited within the callback. When we return, only the + * pointer to t must still exist. */ + UA_ApplicationCallback cb = first->callback; + void *app = first->application; + void *data = first->data; + UA_UNLOCK(&t->timerMutex); + executionCallback(executionApplication, cb, app, data); + UA_LOCK(&t->timerMutex); } /* Return the timestamp of the earliest next callback */ - first = ZIP_MIN(UA_TimerZip, &t->root); - return (first) ? first->nextTime : UA_INT64_MAX; -} - -static void -freeEntry(UA_TimerEntry *te, void *data) { - UA_free(te); + first = (UA_TimerEntry*)aa_min(&t->root); + UA_DateTime next = (first) ? first->nextTime : UA_INT64_MAX; + if(next < nowMonotonic) + next = nowMonotonic; + UA_UNLOCK(&t->timerMutex); + return next; } void -UA_Timer_deleteMembers(UA_Timer *t) { - /* Free all nodes and reset the root */ - ZIP_ITER(UA_TimerZip, &t->root, freeEntry, NULL); - ZIP_INIT(&t->root); +UA_Timer_clear(UA_Timer *t) { + UA_LOCK(&t->timerMutex); + + /* Free all entries */ + UA_TimerEntry *top; + while((top = (UA_TimerEntry*)aa_min(&t->idRoot))) { + aa_remove(&t->idRoot, top); + UA_free(top); + } + + /* Reset the trees to avoid future access */ + t->root.root = NULL; + t->idRoot.root = NULL; + + UA_UNLOCK(&t->timerMutex); +#if UA_MULTITHREADING >= 100 + UA_LOCK_DESTROY(&t->timerMutex); +#endif } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_connection.c" ***********************************/ +/**** amalgamated original file "/src/ua_connection.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -20300,8 +18598,13 @@ UA_Connection_sendError(UA_Connection *connection, UA_TcpErrorMessage *error) { /* Encode and send the response */ UA_Byte *bufPos = msg.data; const UA_Byte *bufEnd = &msg.data[msg.length]; - UA_TcpMessageHeader_encodeBinary(&header, &bufPos, bufEnd); - UA_TcpErrorMessage_encodeBinary(error, &bufPos, bufEnd); + retval |= UA_encodeBinaryInternal(&header, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &bufPos, &bufEnd, NULL, NULL); + retval |= UA_encodeBinaryInternal(error, + &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], + &bufPos, &bufEnd, NULL, NULL); + (void)retval; /* Encoding of these cannot fail */ msg.length = header.messageSize; connection->send(connection, &msg); } @@ -20321,7 +18624,7 @@ UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *c UA_atomic_xchg((void**)&connection->channel, (void*)channel); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_securechannel.c" ***********************************/ +/**** amalgamated original file "/src/ua_securechannel.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -20342,7 +18645,7 @@ UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *c #define UA_BITMASK_MESSAGETYPE 0x00ffffffu #define UA_BITMASK_CHUNKTYPE 0xff000000u -const UA_ByteString UA_SECURITY_POLICY_NONE_URI = +const UA_String UA_SECURITY_POLICY_NONE_URI = {47, (UA_Byte *)"http://opcfoundation.org/UA/SecurityPolicy#None"}; #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS @@ -20355,8 +18658,9 @@ void UA_SecureChannel_init(UA_SecureChannel *channel, const UA_ConnectionConfig *config) { /* Linked lists are also initialized by zeroing out */ memset(channel, 0, sizeof(UA_SecureChannel)); - channel->state = UA_SECURECHANNELSTATE_CLOSED; + channel->state = UA_SECURECHANNELSTATE_FRESH; SIMPLEQ_INIT(&channel->completeChunks); + SIMPLEQ_INIT(&channel->decryptedChunks); SLIST_INIT(&channel->sessions); channel->config = *config; } @@ -20366,52 +18670,53 @@ UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel, const UA_SecurityPolicy *securityPolicy, const UA_ByteString *remoteCertificate) { /* Is a policy already configured? */ - if(channel->securityPolicy) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Security policy already configured"); - return UA_STATUSCODE_BADINTERNALERROR; - } + UA_CHECK_ERROR(!channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR, + securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Security policy already configured"); - UA_StatusCode retval = securityPolicy->channelModule. + /* Create the context */ + UA_StatusCode res = securityPolicy->channelModule. newContext(securityPolicy, remoteCertificate, &channel->channelContext); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Could not set up the SecureChannel context"); - return retval; - } - - retval = UA_ByteString_copy(remoteCertificate, &channel->remoteCertificate); - if(retval != UA_STATUSCODE_GOOD) - return retval; - - UA_ByteString remoteCertificateThumbprint = {20, channel->remoteCertificateThumbprint}; - retval = securityPolicy->asymmetricModule. + res |= UA_ByteString_copy(remoteCertificate, &channel->remoteCertificate); + UA_CHECK_STATUS_WARN(res, return res, securityPolicy->logger, + UA_LOGCATEGORY_SECURITYPOLICY, + "Could not set up the SecureChannel context"); + + /* Compute the certificate thumbprint */ + UA_ByteString remoteCertificateThumbprint = + {20, channel->remoteCertificateThumbprint}; + res = securityPolicy->asymmetricModule. makeCertificateThumbprint(securityPolicy, &channel->remoteCertificate, &remoteCertificateThumbprint); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Could not create the certificate thumbprint"); - return retval; - } + UA_CHECK_STATUS_WARN(res, return res, securityPolicy->logger, + UA_LOGCATEGORY_SECURITYPOLICY, + "Could not create the certificate thumbprint"); + /* Set the policy */ channel->securityPolicy = securityPolicy; return UA_STATUSCODE_GOOD; } static void +UA_Chunk_delete(UA_Chunk *chunk) { + if(chunk->copied) + UA_ByteString_clear(&chunk->bytes); + UA_free(chunk); +} + +static void deleteChunks(UA_ChunkQueue *queue) { UA_Chunk *chunk; while((chunk = SIMPLEQ_FIRST(queue))) { - if(chunk->copied) - UA_ByteString_deleteMembers(&chunk->bytes); SIMPLEQ_REMOVE_HEAD(queue, pointers); - UA_free(chunk); + UA_Chunk_delete(chunk); } } void UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel) { deleteChunks(&channel->completeChunks); + deleteChunks(&channel->decryptedChunks); UA_ByteString_clear(&channel->incompleteChunk); } @@ -20427,12 +18732,16 @@ UA_SecureChannel_close(UA_SecureChannel *channel) { UA_Connection_detachSecureChannel(channel->connection); } - /* Remove session pointers (not the sessions) and NULL the pointers back to - * the SecureChannel in the Session */ + /* Detach Sessions from the SecureChannel. This also removes outstanding + * Publish requests whose RequestId is valid only for the SecureChannel. */ UA_SessionHeader *sh; while((sh = SLIST_FIRST(&channel->sessions))) { - sh->channel = NULL; - SLIST_REMOVE_HEAD(&channel->sessions, next); + if(sh->serverSession) { + UA_Session_detachFromSecureChannel((UA_Session *)sh); + } else { + sh->channel = NULL; + SLIST_REMOVE_HEAD(&channel->sessions, next); + } } /* Delete the channel context for the security policy */ @@ -20478,7 +18787,6 @@ UA_SecureChannel_processHELACK(UA_SecureChannel *channel, return UA_STATUSCODE_BADINTERNALERROR; channel->connection->state = UA_CONNECTIONSTATE_ESTABLISHED; - return UA_STATUSCODE_GOOD; } @@ -20487,23 +18795,18 @@ UA_StatusCode UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 requestId, const void *content, const UA_DataType *contentType) { - if(channel->securityMode == UA_MESSAGESECURITYMODE_INVALID) - return UA_STATUSCODE_BADSECURITYMODEREJECTED; + UA_CHECK(channel->securityMode != UA_MESSAGESECURITYMODE_INVALID, + return UA_STATUSCODE_BADSECURITYMODEREJECTED); const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; - - UA_Connection *connection = channel->connection; - if(!connection) - return UA_STATUSCODE_BADINTERNALERROR; + UA_Connection *conn = channel->connection; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + UA_CHECK_MEM(conn, return UA_STATUSCODE_BADINTERNALERROR); /* Allocate the message buffer */ UA_ByteString buf = UA_BYTESTRING_NULL; - UA_StatusCode retval = - connection->getSendBuffer(connection, channel->config.sendBufferSize, &buf); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = conn->getSendBuffer(conn, channel->config.sendBufferSize, &buf); + UA_CHECK_STATUS(res, return res); /* Restrict buffer to the available space for the payload */ UA_Byte *buf_pos = buf.data; @@ -20511,19 +18814,21 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, hideBytesAsym(channel, &buf_pos, &buf_end); /* Encode the message type and content */ - UA_NodeId typeId = UA_NODEID_NUMERIC(0, contentType->binaryEncodingId); - retval |= UA_encodeBinary(&typeId, &UA_TYPES[UA_TYPES_NODEID], &buf_pos, &buf_end, NULL, NULL); - retval |= UA_encodeBinary(content, contentType, &buf_pos, &buf_end, NULL, NULL); - if(retval != UA_STATUSCODE_GOOD) { - connection->releaseSendBuffer(connection, &buf); - return retval; - } + res |= UA_NodeId_encodeBinary(&contentType->binaryEncodingId, &buf_pos, buf_end); + res |= UA_encodeBinaryInternal(content, contentType, + &buf_pos, &buf_end, NULL, NULL); + UA_CHECK_STATUS(res, conn->releaseSendBuffer(conn, &buf); return res); const size_t securityHeaderLength = calculateAsymAlgSecurityHeaderLength(channel); - /* Add padding to the chunk */ #ifdef UA_ENABLE_ENCRYPTION - padChunkAsym(channel, &buf, securityHeaderLength, &buf_pos); + /* Add padding to the chunk. Also pad if the securityMode is SIGN_ONLY, + * since we are using asymmetric communication to exchange keys and thus + * need to encrypt. */ + if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE) + padChunk(channel, &channel->securityPolicy->asymmetricModule.cryptoModule, + &buf.data[UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength], + &buf_pos); #endif /* The total message length */ @@ -20532,42 +18837,34 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) total_length += sp->asymmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); + getLocalSignatureSize(channel->channelContext); /* The total message length is known here which is why we encode the headers * at this step and not earlier. */ - size_t finalLength = 0; - retval = prependHeadersAsym(channel, buf.data, buf_end, total_length, - securityHeaderLength, requestId, &finalLength); - if(retval != UA_STATUSCODE_GOOD) { - connection->releaseSendBuffer(connection, &buf); - return retval; - } + size_t encryptedLength = 0; + res = prependHeadersAsym(channel, buf.data, buf_end, total_length, + securityHeaderLength, requestId, &encryptedLength); + UA_CHECK_STATUS(res, conn->releaseSendBuffer(conn, &buf); return res); #ifdef UA_ENABLE_ENCRYPTION - retval = signAndEncryptAsym(channel, pre_sig_length, &buf, securityHeaderLength, total_length); - if(retval != UA_STATUSCODE_GOOD) { - connection->releaseSendBuffer(connection, &buf); - return retval; - } + res = signAndEncryptAsym(channel, pre_sig_length, &buf, + securityHeaderLength, total_length); + UA_CHECK_STATUS(res, conn->releaseSendBuffer(conn, &buf); return res); #endif /* Send the message, the buffer is freed in the network layer */ - buf.length = finalLength; - retval = connection->send(connection, &buf); + buf.length = encryptedLength; + res = conn->send(conn, &buf); #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS - retval |= sendAsym_sendFailure; + res |= sendAsym_sendFailure; #endif - return retval; + return res; } /* Will this chunk surpass the capacity of the SecureChannel for the message? */ static UA_StatusCode -checkLimitsSym(UA_MessageContext *const mc, size_t *const bodyLength) { - UA_Byte *buf_body_start = mc->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH; - const UA_Byte *buf_body_end = mc->buf_pos; - *bodyLength = (uintptr_t)buf_body_end - (uintptr_t)buf_body_start; - mc->messageSizeSoFar += *bodyLength; +adjustCheckMessageLimitsSym(UA_MessageContext *mc, size_t bodyLength) { + mc->messageSizeSoFar += bodyLength; mc->chunksSoFar++; UA_SecureChannel *channel = mc->channel; @@ -20583,111 +18880,127 @@ checkLimitsSym(UA_MessageContext *const mc, size_t *const bodyLength) { } static UA_StatusCode -encodeHeadersSym(UA_MessageContext *const messageContext, size_t totalLength) { - UA_SecureChannel *channel = messageContext->channel; - UA_Byte *header_pos = messageContext->messageBuffer.data; +encodeHeadersSym(UA_MessageContext *mc, size_t totalLength) { + UA_SecureChannel *channel = mc->channel; + UA_Byte *header_pos = mc->messageBuffer.data; UA_TcpMessageHeader header; - header.messageTypeAndChunkType = messageContext->messageType; + header.messageTypeAndChunkType = mc->messageType; header.messageSize = (UA_UInt32)totalLength; - if(messageContext->final) + if(mc->final) header.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL; else header.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE; UA_SequenceHeader seqHeader; - seqHeader.requestId = messageContext->requestId; + seqHeader.requestId = mc->requestId; seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1); UA_StatusCode res = UA_STATUSCODE_GOOD; - res |= UA_encodeBinary(&header, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], - &header_pos, &messageContext->buf_end, NULL, NULL); - res |= UA_encodeBinary(&channel->securityToken.channelId, &UA_TYPES[UA_TYPES_UINT32], - &header_pos, &messageContext->buf_end, NULL, NULL); - res |= UA_encodeBinary(&channel->securityToken.tokenId, &UA_TYPES[UA_TYPES_UINT32], - &header_pos, &messageContext->buf_end, NULL, NULL); - res |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], - &header_pos, &messageContext->buf_end, NULL, NULL); + res |= UA_encodeBinaryInternal(&header, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &header_pos, &mc->buf_end, NULL, NULL); + res |= UA_UInt32_encodeBinary(&channel->securityToken.channelId, + &header_pos, mc->buf_end); + res |= UA_UInt32_encodeBinary(&channel->securityToken.tokenId, + &header_pos, mc->buf_end); + res |= UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], + &header_pos, &mc->buf_end, NULL, NULL); return res; } static UA_StatusCode -sendSymmetricChunk(UA_MessageContext *messageContext) { - UA_SecureChannel *const channel = messageContext->channel; - const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; - UA_Connection *const connection = channel->connection; - if(!connection) - return UA_STATUSCODE_BADINTERNALERROR; +sendSymmetricChunk(UA_MessageContext *mc) { + UA_SecureChannel *channel = mc->channel; + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_Connection *connection = channel->connection; + UA_CHECK_MEM(connection, return UA_STATUSCODE_BADINTERNALERROR); - size_t bodyLength = 0; - UA_StatusCode res = checkLimitsSym(messageContext, &bodyLength); - if(res != UA_STATUSCODE_GOOD) - goto error; + /* The size of the message payload */ + size_t bodyLength = (uintptr_t)mc->buf_pos - + (uintptr_t)&mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]; + + /* Early-declare variables so we can use a goto in the error case */ + size_t total_length = 0; + size_t pre_sig_length = 0; + + /* Check if chunk exceeds the limits for the overall message */ + UA_StatusCode res = adjustCheckMessageLimitsSym(mc, bodyLength); + UA_CHECK_STATUS(res, goto error); + + UA_LOG_TRACE_CHANNEL(sp->logger, channel, + "Send from a symmetric message buffer of length %lu " + "a message of header+payload length of %lu", + (long unsigned int)mc->messageBuffer.length, + (long unsigned int) + ((uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data)); - /* Add padding */ #ifdef UA_ENABLE_ENCRYPTION - padChunkSym(messageContext, bodyLength); + /* Add padding if the message is encrypted */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + padChunk(channel, &sp->symmetricModule.cryptoModule, + &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH], + &mc->buf_pos); #endif - /* The total message length */ - size_t pre_sig_length = (uintptr_t)(messageContext->buf_pos) - - (uintptr_t)messageContext->messageBuffer.data; - size_t total_length = pre_sig_length; + /* Compute the total message length */ + pre_sig_length = (uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data; + total_length = pre_sig_length; if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) - total_length += securityPolicy->symmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(securityPolicy, channel->channelContext); + total_length += sp->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + + UA_LOG_TRACE_CHANNEL(sp->logger, channel, + "Send from a symmetric message buffer of length %lu " + "a message of length %lu", + (long unsigned int)mc->messageBuffer.length, + (long unsigned int)total_length); + /* Space for the padding and the signature have been reserved in setBufPos() */ UA_assert(total_length <= channel->config.sendBufferSize); - /* For giving the buffer to the network layer */ - messageContext->messageBuffer.length = total_length; + /* Adjust the buffer size of the network layer */ + mc->messageBuffer.length = total_length; - UA_assert(res == UA_STATUSCODE_GOOD); - res = encodeHeadersSym(messageContext, total_length); - if(res != UA_STATUSCODE_GOOD) - goto error; + /* Generate and encode the header for symmetric messages */ + res = encodeHeadersSym(mc, total_length); + UA_CHECK_STATUS(res, goto error); #ifdef UA_ENABLE_ENCRYPTION - res = signChunkSym(messageContext, pre_sig_length); - if(res != UA_STATUSCODE_GOOD) - goto error; - - res = encryptChunkSym(messageContext, total_length); - if(res != UA_STATUSCODE_GOOD) - goto error; + /* Sign and encrypt the messge */ + res = signAndEncryptSym(mc, pre_sig_length, total_length); + UA_CHECK_STATUS(res, goto error); #endif /* Send the chunk, the buffer is freed in the network layer */ - return connection->send(channel->connection, &messageContext->messageBuffer); + return connection->send(channel->connection, &mc->messageBuffer); -error: - connection->releaseSendBuffer(channel->connection, &messageContext->messageBuffer); + error: + /* Free the unused message buffer */ + connection->releaseSendBuffer(channel->connection, &mc->messageBuffer); return res; } /* Callback from the encoding layer. Send the chunk and replace the buffer. */ static UA_StatusCode -sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf_end) { +sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, + const UA_Byte **buf_end) { /* Set buf values from encoding in the messagecontext */ UA_MessageContext *mc = (UA_MessageContext *)data; mc->buf_pos = *buf_pos; mc->buf_end = *buf_end; /* Send out */ - UA_StatusCode retval = sendSymmetricChunk(mc); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = sendSymmetricChunk(mc); + UA_CHECK_STATUS(res, return res); /* Set a new buffer for the next chunk */ - UA_Connection *connection = mc->channel->connection; - if(!connection) - return UA_STATUSCODE_BADINTERNALERROR; + UA_Connection *c = mc->channel->connection; + UA_CHECK_MEM(c, return UA_STATUSCODE_BADINTERNALERROR); - retval = connection->getSendBuffer(connection, mc->channel->config.sendBufferSize, - &mc->messageBuffer); - if(retval != UA_STATUSCODE_GOOD) - return retval; + res = c->getSendBuffer(c, mc->channel->config.sendBufferSize, + &mc->messageBuffer); + UA_CHECK_STATUS(res, return res); /* Hide bytes for header, padding and signature */ setBufPos(mc); @@ -20699,12 +19012,11 @@ sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf UA_StatusCode UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel, UA_UInt32 requestId, UA_MessageType messageType) { - UA_Connection *connection = channel->connection; - if(!connection) - return UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK(messageType == UA_MESSAGETYPE_MSG || messageType == UA_MESSAGETYPE_CLO, + return UA_STATUSCODE_BADINTERNALERROR); - if(messageType != UA_MESSAGETYPE_MSG && messageType != UA_MESSAGETYPE_CLO) - return UA_STATUSCODE_BADINTERNALERROR; + UA_Connection *c = channel->connection; + UA_CHECK_MEM(c, return UA_STATUSCODE_BADINTERNALERROR); /* Create the chunking info structure */ mc->channel = channel; @@ -20716,11 +19028,9 @@ UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel, mc->messageType = messageType; /* Allocate the message buffer */ - UA_StatusCode retval = - connection->getSendBuffer(connection, channel->config.sendBufferSize, - &mc->messageBuffer); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = c->getSendBuffer(c, channel->config.sendBufferSize, + &mc->messageBuffer); + UA_CHECK_STATUS(res, return res); /* Hide bytes for header, padding and signature */ setBufPos(mc); @@ -20730,11 +19040,12 @@ UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel, UA_StatusCode UA_MessageContext_encode(UA_MessageContext *mc, const void *content, const UA_DataType *contentType) { - UA_StatusCode retval = UA_encodeBinary(content, contentType, &mc->buf_pos, &mc->buf_end, - sendSymmetricEncodingCallback, mc); - if(retval != UA_STATUSCODE_GOOD && mc->messageBuffer.length > 0) + UA_StatusCode res = + UA_encodeBinaryInternal(content, contentType, &mc->buf_pos, &mc->buf_end, + sendSymmetricEncodingCallback, mc); + if(res != UA_STATUSCODE_GOOD && mc->messageBuffer.length > 0) UA_MessageContext_abort(mc); - return retval; + return res; } UA_StatusCode @@ -20763,22 +19074,20 @@ UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 reque return UA_STATUSCODE_BADCONNECTIONCLOSED; UA_MessageContext mc; - UA_StatusCode retval = UA_MessageContext_begin(&mc, channel, requestId, messageType); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = UA_MessageContext_begin(&mc, channel, requestId, messageType); + UA_CHECK_STATUS(res, return res); /* Assert's required for clang-analyzer */ - UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH]); + UA_assert(mc.buf_pos == + &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]); UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]); - UA_NodeId typeId = UA_NODEID_NUMERIC(0, payloadType->binaryEncodingId); - retval = UA_MessageContext_encode(&mc, &typeId, &UA_TYPES[UA_TYPES_NODEID]); - if(retval != UA_STATUSCODE_GOOD) - return retval; + res = UA_MessageContext_encode(&mc, &payloadType->binaryEncodingId, + &UA_TYPES[UA_TYPES_NODEID]); + UA_CHECK_STATUS(res, return res); - retval = UA_MessageContext_encode(&mc, payload, payloadType); - if(retval != UA_STATUSCODE_GOOD) - return retval; + res = UA_MessageContext_encode(&mc, payload, payloadType); + UA_CHECK_STATUS(res, return res); return UA_MessageContext_finish(&mc); } @@ -20787,22 +19096,24 @@ UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 reque /* Receive and Process Messages */ /********************************/ +/* Does the sequence number match? Otherwise try to rollover. See Part 6, + * Section 6.7.2.4 of the standard. */ +#define UA_SEQUENCENUMBER_ROLLOVER 4294966271 + #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION static UA_StatusCode processSequenceNumberSym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) { - /* Failure mode hook for unit tests */ #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + /* Failure mode hook for unit tests */ if(processSym_seqNumberFailure != UA_STATUSCODE_GOOD) return processSym_seqNumberFailure; #endif - /* Does the sequence number match? */ if(sequenceNumber != channel->receiveSequenceNumber + 1) { - /* FIXME: Remove magic numbers :( */ - if(channel->receiveSequenceNumber + 1 > 4294966271 && sequenceNumber < 1024) - channel->receiveSequenceNumber = sequenceNumber - 1; /* Roll over */ - else + if(channel->receiveSequenceNumber + 1 <= UA_SEQUENCENUMBER_ROLLOVER || + sequenceNumber >= 1024) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + channel->receiveSequenceNumber = sequenceNumber - 1; /* Roll over */ } ++channel->receiveSequenceNumber; return UA_STATUSCODE_GOOD; @@ -20810,116 +19121,198 @@ processSequenceNumberSym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) { #endif static UA_StatusCode -decryptVerifySymmetricChunk(UA_SecureChannel *channel, const UA_SecurityPolicy *sp, - UA_Chunk *chunk, UA_UInt32 *requestId) { - size_t offset = 8; /* Skip the message header */ +unpackPayloadOPN(UA_SecureChannel *channel, UA_Chunk *chunk, void *application) { + UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH); + size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */ + UA_UInt32 secureChannelId; + UA_StatusCode res = UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId); + UA_assert(res == UA_STATUSCODE_GOOD); + + UA_AsymmetricAlgorithmSecurityHeader asymHeader; + res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &asymHeader, + &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], NULL); + UA_CHECK_STATUS(res, return res); + + if(asymHeader.senderCertificate.length > 0) { + if(channel->certificateVerification) + res = channel->certificateVerification-> + verifyCertificate(channel->certificateVerification->context, + &asymHeader.senderCertificate); + else + res = UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_STATUS(res, goto error); + } + + /* New channel, create a security policy context and attach */ + if(!channel->securityPolicy) { + if(channel->processOPNHeader) + res = channel->processOPNHeader(application, channel, &asymHeader); + if(!channel->securityPolicy) + res = UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_STATUS(res, goto error); + } + + /* On the client side, take the SecureChannelId from the first response */ + if(secureChannelId != 0 && channel->securityToken.channelId == 0) + channel->securityToken.channelId = secureChannelId; + +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + /* Check the ChannelId. Non-opened channels have the id zero. */ + if(secureChannelId != channel->securityToken.channelId) { + res = UA_STATUSCODE_BADSECURECHANNELIDINVALID; + goto error; + } +#endif + + /* Check the header */ + res = checkAsymHeader(channel, &asymHeader); + UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); + UA_CHECK_STATUS(res, return res); + + /* Decrypt the chunk payload */ + res = decryptAndVerifyChunk(channel, + &channel->securityPolicy->asymmetricModule.cryptoModule, + chunk->messageType, &chunk->bytes, offset); + UA_CHECK_STATUS(res, return res); + + /* Decode the SequenceHeader */ + UA_SequenceHeader sequenceHeader; + res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader, + &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL); + UA_CHECK_STATUS(res, return res); + + /* Set the sequence number for the channel from which to count up */ + channel->receiveSequenceNumber = sequenceHeader.sequenceNumber; + chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */ + + /* Use only the payload */ + chunk->bytes.data += offset; + chunk->bytes.length -= offset; + return UA_STATUSCODE_GOOD; + +error: + UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); + return res; +} + +static UA_StatusCode +unpackPayloadMSG(UA_SecureChannel *channel, UA_Chunk *chunk) { + UA_CHECK_MEM(channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR); + + UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH); + size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */ UA_UInt32 secureChannelId; - UA_UInt32 tokenId; + UA_UInt32 tokenId; /* SymmetricAlgorithmSecurityHeader */ UA_StatusCode res = UA_STATUSCODE_GOOD; res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId); res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &tokenId); - if(res != UA_STATUSCODE_GOOD) - return res; + UA_assert(offset == UA_SECURECHANNEL_MESSAGE_MIN_LENGTH); + UA_assert(res == UA_STATUSCODE_GOOD); #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) /* Check the ChannelId. Non-opened channels have the id zero. */ - if(secureChannelId != channel->securityToken.channelId) - return UA_STATUSCODE_BADSECURECHANNELIDINVALID; + UA_CHECK(secureChannelId == channel->securityToken.channelId, + return UA_STATUSCODE_BADSECURECHANNELIDINVALID); #endif /* Check (and revolve) the SecurityToken */ res = checkSymHeader(channel, tokenId); - if(res != UA_STATUSCODE_GOOD) - return res; + UA_CHECK_STATUS(res, return res); /* Decrypt the chunk payload */ - if(!chunk->decrypted) { - res = decryptAndVerifyChunk(channel, &sp->symmetricModule.cryptoModule, - chunk->messageType, &chunk->bytes, offset); - if(res != UA_STATUSCODE_GOOD) - return res; - chunk->decrypted = true; - } + res = decryptAndVerifyChunk(channel, + &channel->securityPolicy->symmetricModule.cryptoModule, + chunk->messageType, &chunk->bytes, offset); + UA_CHECK_STATUS(res, return res); /* Check the sequence number. Skip sequence number checking for fuzzer to * improve coverage */ UA_SequenceHeader sequenceHeader; - res = UA_SequenceHeader_decodeBinary(&chunk->bytes, &offset, &sequenceHeader); + res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader, + &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION res |= processSequenceNumberSym(channel, sequenceHeader.sequenceNumber); #endif + UA_CHECK_STATUS(res, return res); - *requestId = sequenceHeader.requestId; - return res; + chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */ + + /* Use only the payload */ + chunk->bytes.data += offset; + chunk->bytes.length -= offset; + return UA_STATUSCODE_GOOD; } static UA_StatusCode -assembleProcessMessage(UA_SecureChannel *channel, UA_ChunkQueue *chunks, size_t chunksSize, - UA_UInt32 requestId, UA_MessageType messageType, - void *application, UA_ProcessMessageCallback callback) { - /* Only MSG and CLO messages at this point */ - UA_assert(messageType == UA_MESSAGETYPE_MSG || - messageType == UA_MESSAGETYPE_CLO); +assembleProcessMessage(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback) { + UA_Chunk *chunk = SIMPLEQ_FIRST(&channel->decryptedChunks); + UA_assert(chunk != NULL); - /* Assemble message */ - UA_Chunk *chunk; - UA_ByteString payload; - if(chunksSize > 1) { - /* Compute the full message length. Omit the MessageHeader and - * SequenceHeader. */ - size_t messageLength = 0; - SIMPLEQ_FOREACH(chunk, chunks, pointers) - messageLength += chunk->bytes.length - 24; - - /* Test chunk count against the connection settings */ - if(channel->config.localMaxMessageSize != 0 && - messageLength > channel->config.localMaxMessageSize) - return UA_STATUSCODE_BADRESPONSETOOLARGE; - - /* Allocate memory for the full message */ - UA_StatusCode res = UA_ByteString_allocBuffer(&payload, messageLength); - if(res != UA_STATUSCODE_GOOD) - return res; - - /* Assemble the full message */ - size_t curPos = 0; - SIMPLEQ_FOREACH(chunk, chunks, pointers) { - UA_assert(chunk->bytes.length > 24); - memcpy(&payload.data[curPos], chunk->bytes.data + 24, - chunk->bytes.length - 24); - curPos += chunk->bytes.length - 24; - } - - /* Process the message */ - callback(application, channel, messageType, requestId, &payload); - UA_ByteString_deleteMembers(&payload); - return UA_STATUSCODE_GOOD; + UA_StatusCode res = UA_STATUSCODE_GOOD; + if(chunk->chunkType == UA_CHUNKTYPE_FINAL) { + SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers); + UA_assert(chunk->chunkType == UA_CHUNKTYPE_FINAL); + res = callback(application, channel, chunk->messageType, + chunk->requestId, &chunk->bytes); + UA_Chunk_delete(chunk); + return res; + } + + UA_UInt32 requestId = chunk->requestId; + UA_MessageType messageType = chunk->messageType; + UA_ChunkType chunkType = chunk->chunkType; + UA_assert(chunkType == UA_CHUNKTYPE_INTERMEDIATE); + + size_t messageSize = 0; + SIMPLEQ_FOREACH(chunk, &channel->decryptedChunks, pointers) { + /* Consistency check */ + if(requestId != chunk->requestId) + return UA_STATUSCODE_BADINTERNALERROR; + if(chunkType != chunk->chunkType && chunk->chunkType != UA_CHUNKTYPE_FINAL) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + if(chunk->messageType != messageType) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + + /* Sum up the lengths */ + messageSize += chunk->bytes.length; + if(chunk->chunkType == UA_CHUNKTYPE_FINAL) + break; } + + /* Allocate memory for the full message */ + UA_ByteString payload; + res = UA_ByteString_allocBuffer(&payload, messageSize); + UA_CHECK_STATUS(res, return res); - /* Hide the MessageHeader and SequenceHeader */ - chunk = SIMPLEQ_FIRST(chunks); - payload = chunk->bytes; - UA_assert(chunk->bytes.length > 24); - payload.data += 24; - payload.length -= 24; + /* Assemble the full message */ + size_t offset = 0; + while(true) { + chunk = SIMPLEQ_FIRST(&channel->decryptedChunks); + memcpy(&payload.data[offset], chunk->bytes.data, chunk->bytes.length); + offset += chunk->bytes.length; + SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers); + UA_ChunkType ct = chunk->chunkType; + UA_Chunk_delete(chunk); + if(ct == UA_CHUNKTYPE_FINAL) + break; + } - /* Process the message */ - callback(application, channel, messageType, requestId, &payload); - return UA_STATUSCODE_GOOD; + /* Process the assembled message */ + res = callback(application, channel, messageType, requestId, &payload); + UA_ByteString_clear(&payload); + return res; } static UA_StatusCode -persistCompleteChunks(UA_SecureChannel *channel) { +persistCompleteChunks(UA_ChunkQueue *queue) { UA_Chunk *chunk; - SIMPLEQ_FOREACH(chunk, &channel->completeChunks, pointers) { + SIMPLEQ_FOREACH(chunk, queue, pointers) { if(chunk->copied) continue; UA_ByteString copy; - UA_StatusCode retval = UA_ByteString_copy(&chunk->bytes, ©); - if(retval != UA_STATUSCODE_GOOD) { - UA_SecureChannel_close(channel); - return retval; - } + UA_StatusCode res = UA_ByteString_copy(&chunk->bytes, ©); + UA_CHECK_STATUS(res, return res); chunk->bytes = copy; chunk->copied = true; } @@ -20928,157 +19321,90 @@ persistCompleteChunks(UA_SecureChannel *channel) { static UA_StatusCode persistIncompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer, - size_t offset) { + size_t offset) { UA_assert(channel->incompleteChunk.length == 0); UA_assert(offset < buffer->length); size_t length = buffer->length - offset; - UA_StatusCode retval = UA_ByteString_allocBuffer(&channel->incompleteChunk, length); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = UA_ByteString_allocBuffer(&channel->incompleteChunk, length); + UA_CHECK_STATUS(res, return res); memcpy(channel->incompleteChunk.data, &buffer->data[offset], length); return UA_STATUSCODE_GOOD; } +/* Processes chunks and puts them into the payloads queue. Once a final chunk is + * put into the queue, the message is assembled and the callback is called. The + * queue will be cleared for the next message. */ static UA_StatusCode -processSymmetricChunks(UA_SecureChannel *channel, UA_ChunkQueue *doneChunks, - void *application, UA_ProcessMessageCallback callback) { - /* Channel configured? */ - const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; - - /* Something to do? */ - UA_Chunk *chunk = SIMPLEQ_FIRST(&channel->completeChunks); - if(!chunk) - return UA_STATUSCODE_GOOD; - - /* Compare that the messageType until the final chunk is the same */ - UA_MessageType messageType = chunk->messageType; - - /* Do we have a complete message? */ - UA_ChunkType finalType = UA_CHUNKTYPE_INTERMEDIATE; - size_t chunksSize = 0; - UA_Chunk *finalChunk = NULL; - SIMPLEQ_FOREACH(finalChunk, &channel->completeChunks, pointers) { - chunksSize++; - finalType = finalChunk->chunkType; - if(finalChunk->messageType != messageType) - return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; - if(finalChunk->chunkType != UA_CHUNKTYPE_INTERMEDIATE) - break; - } - - /* Test chunk count against the connection settings */ - if(channel->config.localMaxChunkCount != 0 && - chunksSize > channel->config.localMaxChunkCount) - return UA_STATUSCODE_BADRESPONSETOOLARGE; - - /* No complete mesage received */ - if(finalType == UA_CHUNKTYPE_INTERMEDIATE) - return UA_STATUSCODE_GOOD; - - /* Abort: Remove all chunks for this message */ - if(finalType == UA_CHUNKTYPE_ABORT) { - while((chunk = SIMPLEQ_FIRST(&channel->completeChunks))) { - SIMPLEQ_REMOVE_HEAD(&channel->completeChunks, pointers); - SIMPLEQ_INSERT_TAIL(doneChunks, chunk, pointers); - if(chunk == finalChunk) - break; - } - return UA_STATUSCODE_GOOD; - } - - /* A complete message has been received */ - UA_assert(finalType == UA_CHUNKTYPE_FINAL); - - /* Decrypt and verify the message chunks */ - UA_Boolean first = true; - UA_UInt32 messageRequestId = 0; +processChunks(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback) { + UA_Chunk *chunk; UA_StatusCode res = UA_STATUSCODE_GOOD; while((chunk = SIMPLEQ_FIRST(&channel->completeChunks))) { - /* Move the chunks for this message out of the channel queue */ + /* Remove from the complete-chunk queue */ SIMPLEQ_REMOVE_HEAD(&channel->completeChunks, pointers); - SIMPLEQ_INSERT_TAIL(doneChunks, chunk, pointers); - UA_UInt32 requestId; - res = decryptVerifySymmetricChunk(channel, sp, chunk, &requestId); - if(res != UA_STATUSCODE_GOOD) - return res; - - /* Compare that the requestId is the same for all chunks */ - if(first) { - messageRequestId = requestId; - first = false; - } else if(messageRequestId != requestId) { - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + /* Check, decrypt and unpack the payload */ + if(chunk->messageType == UA_MESSAGETYPE_OPN) { + if(channel->state != UA_SECURECHANNELSTATE_OPEN && + channel->state != UA_SECURECHANNELSTATE_OPN_SENT && + channel->state != UA_SECURECHANNELSTATE_ACK_SENT) + res = UA_STATUSCODE_BADINVALIDSTATE; + else + res = unpackPayloadOPN(channel, chunk, application); + } else if(chunk->messageType == UA_MESSAGETYPE_MSG || + chunk->messageType == UA_MESSAGETYPE_CLO) { + if(channel->state == UA_SECURECHANNELSTATE_CLOSED) + res = UA_STATUSCODE_BADSECURECHANNELCLOSED; + else + res = unpackPayloadMSG(channel, chunk); + } else { + chunk->bytes.data += UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; + chunk->bytes.length -= UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; } - if(chunk == finalChunk) - break; - } - return assembleProcessMessage(channel, doneChunks, chunksSize, messageRequestId, - messageType, application, callback); -} - -static UA_StatusCode -processCompleteChunks(UA_SecureChannel *channel, void *application, - UA_ProcessMessageCallback callback) { - UA_StatusCode res = UA_STATUSCODE_GOOD; - UA_Chunk *chunk = SIMPLEQ_FIRST(&channel->completeChunks); - while(chunk) { - UA_ChunkQueue doneChunks; - SIMPLEQ_INIT(&doneChunks); - switch(chunk->messageType) { - case UA_MESSAGETYPE_HEL: - case UA_MESSAGETYPE_ACK: - case UA_MESSAGETYPE_OPN: - case UA_MESSAGETYPE_ERR: - /* Chunks that are processed entirely by the application */ - SIMPLEQ_REMOVE_HEAD(&channel->completeChunks, pointers); - SIMPLEQ_INSERT_TAIL(&doneChunks, chunk, pointers); - callback(application, channel, chunk->messageType, 0, &chunk->bytes); - break; - default: /* MSG and CLO */ - res = processSymmetricChunks(channel, &doneChunks, application, callback); - break; + if(res != UA_STATUSCODE_GOOD) { + UA_Chunk_delete(chunk); + return res; } - deleteChunks(&doneChunks); - if(res != UA_STATUSCODE_GOOD) - break; + /* Add to the decrypted-chunk queue */ + SIMPLEQ_INSERT_TAIL(&channel->decryptedChunks, chunk, pointers); - /* The channel is shutting down */ - if(channel->state == UA_SECURECHANNELSTATE_CLOSING) - return UA_STATUSCODE_BADCONNECTIONCLOSED; + /* Check the resource limits */ + channel->decryptedChunksCount++; + channel->decryptedChunksLength += chunk->bytes.length; + if((channel->config.localMaxChunkCount != 0 && + channel->decryptedChunksCount > channel->config.localMaxChunkCount) || + (channel->config.localMaxMessageSize != 0 && + channel->decryptedChunksLength > channel->config.localMaxMessageSize)) { + return UA_STATUSCODE_BADTCPMESSAGETOOLARGE; + } - /* Could we process a full message? Done? */ - UA_Chunk *next = SIMPLEQ_FIRST(&channel->completeChunks); - if(chunk == next) - break; - chunk = next; - } + /* Waiting for additional chunks */ + if(chunk->chunkType == UA_CHUNKTYPE_INTERMEDIATE) + continue; - /* Decrypt remaining MSG chunks. But abort before OPN. This allows us to - * decrypt chunks while the rest of the message is still in transit, - * resulting in speed improvements. */ + /* Final chunk or abort. Reset the counters. */ + channel->decryptedChunksCount = 0; + channel->decryptedChunksLength = 0; - /* Channel configured? */ - const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return res; - - SIMPLEQ_FOREACH(chunk, &channel->completeChunks, pointers) { - if(chunk->messageType != UA_MESSAGETYPE_MSG) - break; - if(chunk->decrypted) + /* Abort the message, remove all decrypted chunks + * TODO: Log a warning with the error code */ + if(chunk->chunkType == UA_CHUNKTYPE_ABORT) { + while((chunk = SIMPLEQ_FIRST(&channel->decryptedChunks))) { + SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers); + UA_Chunk_delete(chunk); + } continue; - res = decryptAndVerifyChunk(channel, &sp->symmetricModule.cryptoModule, - chunk->messageType, &chunk->bytes, 16); - if(res != UA_STATUSCODE_GOOD) - break; - chunk->decrypted = true; + } + + /* The decrypted queue contains a full message. Process it. */ + UA_assert(chunk->chunkType == UA_CHUNKTYPE_FINAL); + res = assembleProcessMessage(channel, application, callback); + UA_CHECK_STATUS(res, return res); } - return res; + + return UA_STATUSCODE_GOOD; } static UA_StatusCode @@ -21087,21 +19413,25 @@ extractCompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer, /* At least 8 byte needed for the header. Wait for the next chunk. */ size_t initial_offset = *offset; size_t remaining = buffer->length - initial_offset; - if(remaining < 8) { + if(remaining < UA_SECURECHANNEL_MESSAGEHEADER_LENGTH) { *done = true; return UA_STATUSCODE_GOOD; } /* Decoding cannot fail */ UA_TcpMessageHeader hdr; - UA_TcpMessageHeader_decodeBinary(buffer, &initial_offset, &hdr); + UA_StatusCode res = + UA_decodeBinaryInternal(buffer, &initial_offset, &hdr, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], NULL); + UA_assert(res == UA_STATUSCODE_GOOD); + (void)res; /* pacify compilers if assert is ignored */ UA_MessageType msgType = (UA_MessageType) (hdr.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE); UA_ChunkType chunkType = (UA_ChunkType) (hdr.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE); /* The message size is not allowed */ - if(hdr.messageSize < 16) + if(hdr.messageSize < UA_SECURECHANNEL_MESSAGE_MIN_LENGTH) return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; if(hdr.messageSize > channel->config.recvBufferSize) return UA_STATUSCODE_BADTCPMESSAGETOOLARGE; @@ -21117,38 +19447,33 @@ extractCompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer, chunkPayload.data = &buffer->data[*offset]; chunkPayload.length = hdr.messageSize; - /* Connection-level messages. These are forwarded entirely. OPN message are - * also forwarded undecrypted */ if(msgType == UA_MESSAGETYPE_HEL || msgType == UA_MESSAGETYPE_ACK || msgType == UA_MESSAGETYPE_ERR || msgType == UA_MESSAGETYPE_OPN) { if(chunkType != UA_CHUNKTYPE_FINAL) return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; - goto add_chunk; - } - - /* Only messages on SecureChannel-level with symmetric encryption afterwards */ - if(msgType != UA_MESSAGETYPE_MSG && - msgType != UA_MESSAGETYPE_CLO) - return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } else { + /* Only messages on SecureChannel-level with symmetric encryption afterwards */ + if(msgType != UA_MESSAGETYPE_MSG && + msgType != UA_MESSAGETYPE_CLO) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; - /* Check the chunk type before decrypting */ - if(chunkType != UA_CHUNKTYPE_FINAL && - chunkType != UA_CHUNKTYPE_INTERMEDIATE && - chunkType != UA_CHUNKTYPE_ABORT) - return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + /* Check the chunk type before decrypting */ + if(chunkType != UA_CHUNKTYPE_FINAL && + chunkType != UA_CHUNKTYPE_INTERMEDIATE && + chunkType != UA_CHUNKTYPE_ABORT) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } - add_chunk: /* Add the chunk; forward the offset */ *offset += hdr.messageSize; UA_Chunk *chunk = (UA_Chunk*)UA_malloc(sizeof(UA_Chunk)); - if(!chunk) - return UA_STATUSCODE_BADOUTOFMEMORY; + UA_CHECK_MEM(chunk, return UA_STATUSCODE_BADOUTOFMEMORY); + chunk->bytes = chunkPayload; chunk->messageType = msgType; chunk->chunkType = chunkType; - chunk->bytes = chunkPayload; + chunk->requestId = 0; chunk->copied = false; - chunk->decrypted = false; SIMPLEQ_INSERT_TAIL(&channel->completeChunks, chunk, pointers); return UA_STATUSCODE_GOOD; @@ -21165,10 +19490,8 @@ UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application, if(appended.length > 0) { channel->incompleteChunk = UA_BYTESTRING_NULL; UA_Byte *t = (UA_Byte*)UA_realloc(appended.data, appended.length + buffer->length); - if(!t) { - UA_ByteString_deleteMembers(&appended); - return UA_STATUSCODE_BADOUTOFMEMORY; - } + UA_CHECK_MEM(t, UA_ByteString_clear(&appended); + return UA_STATUSCODE_BADOUTOFMEMORY); memcpy(&t[appended.length], buffer->data, buffer->length); appended.data = t; appended.length += buffer->length; @@ -21178,32 +19501,31 @@ UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application, /* Loop over the received chunks */ size_t offset = 0; UA_Boolean done = false; - UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_StatusCode res; while(!done) { res = extractCompleteChunk(channel, buffer, &offset, &done); - if(res != UA_STATUSCODE_GOOD) - goto cleanup; + UA_CHECK_STATUS(res, goto cleanup); } /* Buffer half-received chunk. Before processing the messages so that * processing is reentrant. */ if(offset < buffer->length) { res = persistIncompleteChunk(channel, buffer, offset); - if(res != UA_STATUSCODE_GOOD) - goto cleanup; + UA_CHECK_STATUS(res, goto cleanup); } /* Process whatever we can. Chunks of completed and processed messages are * removed. */ - res = processCompleteChunks(channel, application, callback); - if(res != UA_STATUSCODE_GOOD) - goto cleanup; + res = processChunks(channel, application, callback); + UA_CHECK_STATUS(res, goto cleanup); - /* Persist full chunks that still point to the buffer */ - res = persistCompleteChunks(channel); + /* Persist full chunks that still point to the buffer. Can only return + * UA_STATUSCODE_BADOUTOFMEMORY as an error code. So merging res works. */ + res |= persistCompleteChunks(&channel->completeChunks); + res |= persistCompleteChunks(&channel->decryptedChunks); cleanup: - UA_ByteString_deleteMembers(&appended); + UA_ByteString_clear(&appended); return res; } @@ -21211,22 +19533,20 @@ UA_StatusCode UA_SecureChannel_receive(UA_SecureChannel *channel, void *application, UA_ProcessMessageCallback callback, UA_UInt32 timeout) { UA_Connection *connection = channel->connection; - if(!connection) - return UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_MEM(connection, return UA_STATUSCODE_BADINTERNALERROR); /* Listen for messages to arrive */ UA_ByteString buffer = UA_BYTESTRING_NULL; - UA_StatusCode retval = connection->recv(connection, &buffer, timeout); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = connection->recv(connection, &buffer, timeout); + UA_CHECK_STATUS(res, return res); /* Try to process one complete chunk */ - retval = UA_SecureChannel_processBuffer(channel, application, callback, &buffer); + res = UA_SecureChannel_processBuffer(channel, application, callback, &buffer); connection->releaseRecvBuffer(connection, &buffer); - return retval; + return res; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_securechannel_crypto.c" ***********************************/ +/**** amalgamated original file "/src/ua_securechannel_crypto.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -21243,39 +19563,28 @@ UA_SecureChannel_receive(UA_SecureChannel *channel, void *application, -#define UA_ASYMMETRIC_ALG_SECURITY_HEADER_FIXED_LENGTH 12 -#define UA_SEQUENCE_HEADER_LENGTH 8 -#define UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH 4 -#define UA_SECUREMH_AND_SYMALGH_LENGTH \ - (UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + \ - UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH) - UA_StatusCode UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel) { const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; - + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local nonce"); /* Is the length of the previous nonce correct? */ size_t nonceLength = sp->symmetricModule.secureChannelNonceLength; if(channel->localNonce.length != nonceLength) { UA_ByteString_clear(&channel->localNonce); - UA_StatusCode retval = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_StatusCode res = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength); + UA_CHECK_STATUS(res, return res); } - return sp->symmetricModule.generateNonce(sp, &channel->localNonce); + /* Generate the nonce */ + return sp->symmetricModule.generateNonce(sp->policyContext, &channel->localNonce); } UA_StatusCode UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel) { const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; - + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Generating new local keys"); void *cc = channel->channelContext; @@ -21283,29 +19592,35 @@ UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel) { const UA_SecurityPolicySymmetricModule *sm = &sp->symmetricModule; const UA_SecurityPolicyCryptoModule *crm = &sm->cryptoModule; - /* Generate symmetric key buffer of the required length */ + /* Generate symmetric key buffer of the required length. The block size is + * identical for local/remote. */ UA_ByteString buf; - size_t encrKL = crm->encryptionAlgorithm.getLocalKeyLength(sp, cc); - size_t encrBS = crm->encryptionAlgorithm.getLocalBlockSize(sp, cc); - size_t signKL = crm->signatureAlgorithm.getLocalKeyLength(sp, cc); + size_t encrKL = crm->encryptionAlgorithm.getLocalKeyLength(cc); + size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(cc); + size_t signKL = crm->signatureAlgorithm.getLocalKeyLength(cc); + if(encrBS + signKL + encrKL == 0) + return UA_STATUSCODE_GOOD; /* No keys to generate */ + UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, encrBS + signKL + encrKL); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_CHECK_STATUS(retval, return retval); + UA_ByteString localSigningKey = {signKL, buf.data}; + UA_ByteString localEncryptingKey = {encrKL, &buf.data[signKL]}; + UA_ByteString localIv = {encrBS, &buf.data[signKL + encrKL]}; /* Generate key */ - retval = sm->generateKey(sp, &channel->remoteNonce, &channel->localNonce, &buf); - if(retval != UA_STATUSCODE_GOOD) { - UA_ByteString_clear(&buf); - return retval; - } + retval = sm->generateKey(sp->policyContext, &channel->remoteNonce, + &channel->localNonce, &buf); + UA_CHECK_STATUS(retval, goto error); /* Set the channel context */ - const UA_ByteString localSigningKey = {signKL, buf.data}; - const UA_ByteString localEncryptingKey = {encrKL, &buf.data[signKL]}; - const UA_ByteString localIv = {encrBS, &buf.data[signKL + encrKL]}; retval |= cm->setLocalSymSigningKey(cc, &localSigningKey); retval |= cm->setLocalSymEncryptingKey(cc, &localEncryptingKey); retval |= cm->setLocalSymIv(cc, &localIv); + + error: + UA_CHECK_STATUS(retval, UA_LOG_WARNING_CHANNEL(sp->logger, channel, + "Could not generate local keys (statuscode: %s)", + UA_StatusCode_name(retval))); UA_ByteString_clear(&buf); return retval; } @@ -21313,9 +19628,7 @@ UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel) { UA_StatusCode generateRemoteKeys(const UA_SecureChannel *channel) { const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; - + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Generating new remote keys"); void *cc = channel->channelContext; @@ -21325,27 +19638,32 @@ generateRemoteKeys(const UA_SecureChannel *channel) { /* Generate symmetric key buffer of the required length */ UA_ByteString buf; - size_t encrKL = crm->encryptionAlgorithm.getRemoteKeyLength(sp, cc); - size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(sp, cc); - size_t signKL = crm->signatureAlgorithm.getRemoteKeyLength(sp, cc); + size_t encrKL = crm->encryptionAlgorithm.getRemoteKeyLength(cc); + size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(cc); + size_t signKL = crm->signatureAlgorithm.getRemoteKeyLength(cc); + if(encrBS + signKL + encrKL == 0) + return UA_STATUSCODE_GOOD; /* No keys to generate */ + UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, encrBS + signKL + encrKL); - if(retval != UA_STATUSCODE_GOOD) { - UA_ByteString_clear(&buf); - return retval; - } + UA_CHECK_STATUS(retval, return retval); + UA_ByteString remoteSigningKey = {signKL, buf.data}; + UA_ByteString remoteEncryptingKey = {encrKL, &buf.data[signKL]}; + UA_ByteString remoteIv = {encrBS, &buf.data[signKL + encrKL]}; /* Generate key */ - retval = sm->generateKey(sp, &channel->localNonce, &channel->remoteNonce, &buf); - if(retval != UA_STATUSCODE_GOOD) - return retval; + retval = sm->generateKey(sp->policyContext, &channel->localNonce, + &channel->remoteNonce, &buf); + UA_CHECK_STATUS(retval, goto error); /* Set the channel context */ - const UA_ByteString remoteSigningKey = {signKL, buf.data}; - const UA_ByteString remoteEncryptingKey = {encrKL, &buf.data[signKL]}; - const UA_ByteString remoteIv = {encrBS, &buf.data[signKL + encrKL]}; retval |= cm->setRemoteSymSigningKey(cc, &remoteSigningKey); retval |= cm->setRemoteSymEncryptingKey(cc, &remoteEncryptingKey); retval |= cm->setRemoteSymIv(cc, &remoteIv); + + error: + UA_CHECK_STATUS(retval, UA_LOG_WARNING_CHANNEL(sp->logger, channel, + "Could not generate remote keys (statuscode: %s)", + UA_StatusCode_name(retval))); UA_ByteString_clear(&buf); return retval; } @@ -21354,16 +19672,17 @@ generateRemoteKeys(const UA_SecureChannel *channel) { /* Send Asymmetric Message */ /***************************/ +/* The length of the static header content */ +#define UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH 12 + size_t calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel) { const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); - size_t asymHeaderLength = UA_ASYMMETRIC_ALG_SECURITY_HEADER_FIXED_LENGTH + + size_t asymHeaderLength = UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH + sp->policyUri.length; - if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && - channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) return asymHeaderLength; /* OPN is always encrypted even if the mode is sign only */ @@ -21376,28 +19695,36 @@ UA_StatusCode prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos, const UA_Byte *buf_end, size_t totalLength, size_t securityHeaderLength, UA_UInt32 requestId, - size_t *const finalLength) { + size_t *const encryptedLength) { const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); - size_t dataToEncryptLength = - totalLength - (UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + securityHeaderLength); + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) { + *encryptedLength = totalLength; + } else { + size_t dataToEncryptLength = totalLength - + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength); + size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext); + size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemoteBlockSize(channel->channelContext); + + /* Padding always fills up the last block */ + UA_assert(dataToEncryptLength % plainTextBlockSize == 0); + size_t blocks = dataToEncryptLength / plainTextBlockSize; + *encryptedLength = totalLength + blocks * (encryptedBlockSize - plainTextBlockSize); + } UA_TcpMessageHeader messageHeader; messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL; - messageHeader.messageSize = (UA_UInt32) - (totalLength + - UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(sp, channel->channelContext, - dataToEncryptLength)); + messageHeader.messageSize = (UA_UInt32)*encryptedLength; UA_UInt32 secureChannelId = channel->securityToken.channelId; UA_StatusCode retval = UA_STATUSCODE_GOOD; - retval |= UA_encodeBinary(&messageHeader, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], - &header_pos, &buf_end, NULL, NULL); - retval |= UA_encodeBinary(&secureChannelId, &UA_TYPES[UA_TYPES_UINT32], - &header_pos, &buf_end, NULL, NULL); - if(retval != UA_STATUSCODE_GOOD) - return retval; + retval |= UA_encodeBinaryInternal(&messageHeader, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &header_pos, &buf_end, NULL, NULL); + retval |= UA_UInt32_encodeBinary(&secureChannelId, &header_pos, buf_end); + UA_CHECK_STATUS(retval, return retval); UA_AsymmetricAlgorithmSecurityHeader asymHeader; UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); @@ -21408,94 +19735,91 @@ prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos, asymHeader.receiverCertificateThumbprint.length = 20; asymHeader.receiverCertificateThumbprint.data = channel->remoteCertificateThumbprint; } - retval = UA_encodeBinary(&asymHeader, - &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], - &header_pos, &buf_end, NULL, NULL); - if(retval != UA_STATUSCODE_GOOD) - return retval; + retval = UA_encodeBinaryInternal(&asymHeader, + &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], + &header_pos, &buf_end, NULL, NULL); + UA_CHECK_STATUS(retval, return retval); UA_SequenceHeader seqHeader; seqHeader.requestId = requestId; seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1); - retval = UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], - &header_pos, &buf_end, NULL, NULL); - - *finalLength = messageHeader.messageSize; - + retval = UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], + &header_pos, &buf_end, NULL, NULL); return retval; } void hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, const UA_Byte **buf_end) { - *buf_start += UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH; + /* Set buf_start to the beginning of the payload body */ + *buf_start += UA_SECURECHANNEL_CHANNELHEADER_LENGTH; *buf_start += calculateAsymAlgSecurityHeaderLength(channel); - *buf_start += UA_SEQUENCE_HEADER_LENGTH; + *buf_start += UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH; #ifdef UA_ENABLE_ENCRYPTION - if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && - channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) return; + /* Make space for the certificate */ const UA_SecurityPolicy *sp = channel->securityPolicy; - - /* Hide bytes for signature and padding */ - size_t potentialEncryptMaxSize = (size_t)(*buf_end - *buf_start) + UA_SEQUENCE_HEADER_LENGTH; *buf_end -= sp->asymmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); - *buf_end -= 2; /* padding byte and extraPadding byte */ + getLocalSignatureSize(channel->channelContext); - /* Add some overhead length due to RSA implementations adding a signature themselves */ - *buf_end -= UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(sp, - channel->channelContext, - potentialEncryptMaxSize); + /* Block sizes depend on the remote key (certificate) */ + size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext); + size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemoteBlockSize(channel->channelContext); + UA_Boolean extraPadding = (sp->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteKeyLength(channel->channelContext) > 2048); + + /* Compute the maximum number of encrypted blocks that can fit entirely + * before the signature. From that compute the maximum usable plaintext + * size. */ + size_t maxEncrypted = (size_t)(*buf_end - *buf_start) + + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH; + size_t max_blocks = maxEncrypted / encryptedBlockSize; + size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u; + *buf_end = *buf_start + (max_blocks * plainTextBlockSize) - + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH - paddingBytes; #endif } #ifdef UA_ENABLE_ENCRYPTION +/* Assumes that pos can be advanced to the end of the current block */ void -padChunkAsym(UA_SecureChannel *channel, const UA_ByteString *buf, - size_t securityHeaderLength, UA_Byte **buf_pos) { - const UA_SecurityPolicy *sp = channel->securityPolicy; +padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm, + const UA_Byte *start, UA_Byte **pos) { + const size_t bytesToWrite = (uintptr_t)*pos - (uintptr_t)start; + size_t signatureSize = cm->signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + size_t plainTextBlockSize = cm->encryptionAlgorithm. + getRemotePlainTextBlockSize(channel->channelContext); + UA_Boolean extraPadding = (cm->encryptionAlgorithm. + getRemoteKeyLength(channel->channelContext) > 2048); + size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u; + + size_t lastBlock = ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize); + size_t paddingLength = (lastBlock != 0) ? plainTextBlockSize - lastBlock : 0; - /* Also pad if the securityMode is SIGN_ONLY, since we are using - * asymmetric communication to exchange keys and thus need to encrypt. */ - if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && - channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) - return; + UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, + "Add %lu bytes of padding plus %lu padding size bytes", + (long unsigned int)paddingLength, + (long unsigned int)paddingBytes); - const UA_Byte *buf_body_start = - &buf->data[UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + - UA_SEQUENCE_HEADER_LENGTH + securityHeaderLength]; - const size_t bytesToWrite = - (uintptr_t)*buf_pos - (uintptr_t)buf_body_start + UA_SEQUENCE_HEADER_LENGTH; - - /* Compute the padding length */ - size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule.encryptionAlgorithm. - getRemotePlainTextBlockSize(sp, channel->channelContext); - size_t signatureSize = sp->asymmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); - size_t paddingBytes = 1; - if(sp->asymmetricModule.cryptoModule.encryptionAlgorithm. - getRemoteKeyLength(sp, channel->channelContext) > 2048) - ++paddingBytes; /* extra padding */ - size_t totalPaddingSize = - (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize)); - - /* Write the padding. This is <= because the paddingSize byte also has to be written */ - UA_Byte paddingSize = (UA_Byte)(totalPaddingSize & 0xffu); - for(UA_UInt16 i = 0; i <= totalPaddingSize; ++i) { - **buf_pos = paddingSize; - ++*buf_pos; + /* Write the padding. This is <= because the paddingSize byte also has to be + * written */ + UA_Byte paddingByte = (UA_Byte)paddingLength; + for(UA_UInt16 i = 0; i <= paddingLength; ++i) { + **pos = paddingByte; + ++*pos; } /* Write the extra padding byte if required */ - if(sp->asymmetricModule.cryptoModule.encryptionAlgorithm. - getRemoteKeyLength(sp, channel->channelContext) > 2048) { - UA_Byte extraPaddingSize = (UA_Byte)(totalPaddingSize >> 8u); - **buf_pos = extraPaddingSize; - ++*buf_pos; + if(extraPadding) { + **pos = (UA_Byte)(paddingLength >> 8u); + ++*pos; } } @@ -21507,154 +19831,110 @@ signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength, channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) return UA_STATUSCODE_GOOD; - const UA_SecurityPolicy *sp = channel->securityPolicy; - /* Sign message */ + const UA_SecurityPolicy *sp = channel->securityPolicy; const UA_ByteString dataToSign = {preSignLength, buf->data}; size_t sigsize = sp->asymmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); + getLocalSignatureSize(channel->channelContext); UA_ByteString signature = {sigsize, buf->data + preSignLength}; UA_StatusCode retval = sp->asymmetricModule.cryptoModule.signatureAlgorithm. - sign(sp, channel->channelContext, &dataToSign, &signature); - if(retval != UA_STATUSCODE_GOOD) - return retval; + sign(channel->channelContext, &dataToSign, &signature); + UA_CHECK_STATUS(retval, return retval); /* Specification part 6, 6.7.4: The OpenSecureChannel Messages are * signed and encrypted if the SecurityMode is not None (even if the * SecurityMode is SignOnly). */ size_t unencrypted_length = - UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + securityHeaderLength; + UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength; UA_ByteString dataToEncrypt = {totalLength - unencrypted_length, &buf->data[unencrypted_length]}; return sp->asymmetricModule.cryptoModule.encryptionAlgorithm. - encrypt(sp, channel->channelContext, &dataToEncrypt); + encrypt(channel->channelContext, &dataToEncrypt); } /**************************/ /* Send Symmetric Message */ /**************************/ -static UA_UInt16 -calculatePaddingSym(const UA_SecurityPolicy *sp, const void *channelContext, - size_t bytesToWrite, UA_Byte *paddingSize, UA_Byte *extraPaddingSize) { - size_t encryptionBlockSize = sp->symmetricModule.cryptoModule. - encryptionAlgorithm.getLocalBlockSize(sp, channelContext); - size_t signatureSize = sp->symmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channelContext); - - size_t padding = (encryptionBlockSize - - ((bytesToWrite + signatureSize + 1) % encryptionBlockSize)); - *paddingSize = (UA_Byte)padding; - *extraPaddingSize = (UA_Byte)(padding >> 8u); - return (UA_UInt16)padding; -} - -void -padChunkSym(UA_MessageContext *messageContext, size_t bodyLength) { - if(messageContext->channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) - return; - - /* The bytes for the padding and signature were removed from buf_end before - * encoding the payload. So we don't have to check if there is enough - * space. */ - - size_t bytesToWrite = bodyLength + UA_SEQUENCE_HEADER_LENGTH; - UA_Byte paddingSize = 0; - UA_Byte extraPaddingSize = 0; - UA_UInt16 totalPaddingSize = - calculatePaddingSym(messageContext->channel->securityPolicy, - messageContext->channel->channelContext, - bytesToWrite, &paddingSize, &extraPaddingSize); - - /* This is <= because the paddingSize byte also has to be written. */ - for(UA_UInt16 i = 0; i <= totalPaddingSize; ++i) { - *messageContext->buf_pos = paddingSize; - ++(messageContext->buf_pos); - } - if(extraPaddingSize > 0) { - *messageContext->buf_pos = extraPaddingSize; - ++(messageContext->buf_pos); - } -} - UA_StatusCode -signChunkSym(UA_MessageContext *const messageContext, size_t preSigLength) { +signAndEncryptSym(UA_MessageContext *messageContext, + size_t preSigLength, size_t totalLength) { const UA_SecureChannel *channel = messageContext->channel; - if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && - channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) return UA_STATUSCODE_GOOD; + /* Sign */ const UA_SecurityPolicy *sp = channel->securityPolicy; UA_ByteString dataToSign = messageContext->messageBuffer; dataToSign.length = preSigLength; UA_ByteString signature; signature.length = sp->symmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); + getLocalSignatureSize(channel->channelContext); signature.data = messageContext->buf_pos; + UA_StatusCode res = sp->symmetricModule.cryptoModule.signatureAlgorithm. + sign(channel->channelContext, &dataToSign, &signature); + UA_CHECK_STATUS(res, return res); - return sp->symmetricModule.cryptoModule.signatureAlgorithm. - sign(sp, channel->channelContext, &dataToSign, &signature); -} - -UA_StatusCode -encryptChunkSym(UA_MessageContext *const messageContext, size_t totalLength) { - const UA_SecureChannel *channel = messageContext->channel; if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) return UA_STATUSCODE_GOOD; - - UA_ByteString dataToEncrypt; - dataToEncrypt.data = messageContext->messageBuffer.data + UA_SECUREMH_AND_SYMALGH_LENGTH; - dataToEncrypt.length = totalLength - UA_SECUREMH_AND_SYMALGH_LENGTH; - const UA_SecurityPolicy *sp = channel->securityPolicy; + /* Encrypt */ + UA_ByteString dataToEncrypt; + dataToEncrypt.data = messageContext->messageBuffer.data + + UA_SECURECHANNEL_CHANNELHEADER_LENGTH + + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH; + dataToEncrypt.length = totalLength - + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH); return sp->symmetricModule.cryptoModule.encryptionAlgorithm. - encrypt(sp, channel->channelContext, &dataToEncrypt); + encrypt(channel->channelContext, &dataToEncrypt); } #endif /* UA_ENABLE_ENCRYPTION */ void setBufPos(UA_MessageContext *mc) { - /* Forward the data pointer so that the payload is encoded after the - * message header */ - mc->buf_pos = &mc->messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH]; + /* Forward the data pointer so that the payload is encoded after the message + * header. This has to be a symmetric message because OPN (with asymmetric + * encryption) does not support chunking. */ + mc->buf_pos = &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]; mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length]; #ifdef UA_ENABLE_ENCRYPTION + if(mc->channel->securityMode == UA_MESSAGESECURITYMODE_NONE) + return; + const UA_SecureChannel *channel = mc->channel; const UA_SecurityPolicy *sp = channel->securityPolicy; + size_t sigsize = sp->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + size_t plainBlockSize = sp->symmetricModule.cryptoModule. + encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext); + + /* Assuming that for symmetric encryption the plainTextBlockSize == + * cypherTextBlockSize. For symmetric encryption the remote/local block + * sizes are identical. */ + UA_assert(sp->symmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteBlockSize(channel->channelContext) == plainBlockSize); + + /* Leave enough space for the signature and padding */ + mc->buf_end -= sigsize; + mc->buf_end -= mc->messageBuffer.length % plainBlockSize; - /* Reserve space for the message footer at the end of the chunk if the chunk - * is signed and/or encrypted. The footer includes the fields PaddingSize, - * Padding, ExtraPadding and Signature. The padding fields are only present - * if the chunk is encrypted. */ - if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || - channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) - mc->buf_end -= sp->symmetricModule.cryptoModule.signatureAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); - - /* The size of the padding depends on the amount of data that shall be sent - * and is unknown at this point. Reserve space for the PaddingSize byte, - * the maximum amount of Padding which equals the block size of the - * symmetric encryption algorithm and last 1 byte for the ExtraPaddingSize - * field that is present if the encryption key is larger than 2048 bits. - * The actual padding size is later calculated by the function - * calculatePaddingSym(). */ if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { - /* PaddingSize and ExtraPaddingSize fields */ - size_t encryptionBlockSize = sp->symmetricModule.cryptoModule. - encryptionAlgorithm.getLocalBlockSize(sp, channel->channelContext); - mc->buf_end -= 1 + ((encryptionBlockSize >> 8u) ? 1 : 0); - - /* Reduce the message body size with the remainder of the operation - * maxEncryptedDataSize modulo EncryptionBlockSize to get a whole - * number of blocks to encrypt later. Also reserve one byte for - * padding (1 <= paddingSize <= encryptionBlockSize). */ - size_t maxEncryptDataSize = mc->messageBuffer.length - - UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH - - UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH; - mc->buf_end -= (maxEncryptDataSize % encryptionBlockSize) + 1; - } + /* Reserve space for the padding bytes */ + UA_Boolean extraPadding = + (sp->symmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteKeyLength(channel->channelContext) > 2048); + mc->buf_end -= (UA_LIKELY(!extraPadding)) ? 1 : 2; + } + + UA_LOG_TRACE_CHANNEL(sp->logger, channel, + "Prepare a symmetric message buffer of length %lu " + "with a usable maximum payload length of %lu", + (long unsigned)mc->messageBuffer.length, + (long unsigned)((uintptr_t)mc->buf_end - + (uintptr_t)mc->messageBuffer.data)); #endif } @@ -21662,36 +19942,23 @@ setBufPos(UA_MessageContext *mc) { /* Process a received Chunk */ /****************************/ -static UA_UInt16 -decodeChunkPadding(const UA_SecureChannel *channel, - const UA_SecurityPolicyCryptoModule *cryptoModule, - UA_MessageType messageType, const UA_ByteString *chunk, - size_t sigsize) { - /* Is padding used? */ - if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT && - !(messageType == UA_MESSAGETYPE_OPN && - !UA_String_equal(&cryptoModule->encryptionAlgorithm.uri, &UA_STRING_NULL))) - return 0; - +static size_t +decodePadding(const UA_SecureChannel *channel, + const UA_SecurityPolicyCryptoModule *cryptoModule, + const UA_ByteString *chunk, size_t sigsize) { + /* Read the byte with the padding size */ size_t paddingSize = chunk->data[chunk->length - sigsize - 1]; /* Extra padding size */ - size_t keyLength = cryptoModule->encryptionAlgorithm. - getLocalKeyLength(channel->securityPolicy, channel->channelContext); - if(keyLength > 2048) { + if(cryptoModule->encryptionAlgorithm. + getLocalKeyLength(channel->channelContext) > 2048) { paddingSize <<= 8u; - paddingSize += 1; paddingSize += chunk->data[chunk->length - sigsize - 2]; + paddingSize += 1; /* Extra padding byte itself */ } - /* We need to add one to the padding size since the paddingSize byte itself - * need to be removed as well. */ - paddingSize += 1; - - UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, - "Calculated padding size to be %lu", - (long unsigned int)paddingSize); - return (UA_UInt16)paddingSize; + /* Add one since the paddingSize byte itself needs to be removed as well */ + return paddingSize + 1; } static UA_StatusCode @@ -21700,12 +19967,11 @@ verifySignature(const UA_SecureChannel *channel, const UA_ByteString *chunk, size_t sigsize) { UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, "Verifying chunk signature"); - if(sigsize >= chunk->length) - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + UA_CHECK(sigsize < chunk->length, return UA_STATUSCODE_BADSECURITYCHECKSFAILED); const UA_ByteString content = {chunk->length - sigsize, chunk->data}; const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize}; UA_StatusCode retval = cryptoModule->signatureAlgorithm. - verify(channel->securityPolicy, channel->channelContext, &content, &sig); + verify(channel->channelContext, &content, &sig); #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS retval |= decrypt_verifySignatureFailure; #endif @@ -21721,15 +19987,12 @@ decryptAndVerifyChunk(const UA_SecureChannel *channel, size_t offset) { /* Decrypt the chunk */ UA_StatusCode res = UA_STATUSCODE_GOOD; - const UA_SecurityPolicy *sp = channel->securityPolicy; if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || messageType == UA_MESSAGETYPE_OPN) { - UA_ByteString cipherText = {chunk->length - offset, chunk->data + offset}; - res = cryptoModule->encryptionAlgorithm. - decrypt(sp, channel->channelContext, &cipherText); - if(res != UA_STATUSCODE_GOOD) - return res; - chunk->length = cipherText.length + offset; + UA_ByteString cipher = {chunk->length - offset, chunk->data + offset}; + res = cryptoModule->encryptionAlgorithm.decrypt(channel->channelContext, &cipher); + UA_CHECK_STATUS(res, return res); + chunk->length = cipher.length + offset; } /* Does the message have a signature? */ @@ -21740,27 +20003,33 @@ decryptAndVerifyChunk(const UA_SecureChannel *channel, /* Verify the chunk signature */ size_t sigsize = cryptoModule->signatureAlgorithm. - getRemoteSignatureSize(sp, channel->channelContext); + getRemoteSignatureSize(channel->channelContext); res = verifySignature(channel, cryptoModule, chunk, sigsize); - if(res != UA_STATUSCODE_GOOD) - return res; + UA_CHECK_STATUS(res, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Could not verify the signature"); return res); - /* Compute and verify the padding. The encrypted payload has to be at least - * 9 bytes long (8 byte for the SequenceHeader and one byte for the actual - * message). */ - size_t paddingSize = - decodeChunkPadding(channel, cryptoModule, messageType, chunk, sigsize); - if(offset + paddingSize + sigsize + 9 >= chunk->length) - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + /* Compute the padding if the payload as encrypted */ + size_t padSize = 0; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || + (messageType == UA_MESSAGETYPE_OPN && + cryptoModule->encryptionAlgorithm.uri.length > 0)) { + padSize = decodePadding(channel, cryptoModule, chunk, sigsize); + UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, + "Calculated padding size to be %lu", + (long unsigned)padSize); + } + + /* Verify the content length. The encrypted payload has to be at least 9 + * bytes long: 8 byte for the SequenceHeader and one byte for the actual + * message */ + UA_CHECK(offset + padSize + sigsize + 9 < chunk->length, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Impossible padding value"); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED); /* Hide the signature and padding */ - chunk->length -= (sigsize + paddingSize); - return UA_STATUSCODE_GOOD; -} - -UA_StatusCode -processSequenceNumberAsym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) { - channel->receiveSequenceNumber = sequenceNumber; + chunk->length -= (sigsize + padSize); return UA_STATUSCODE_GOOD; } @@ -21768,7 +20037,6 @@ UA_StatusCode checkAsymHeader(UA_SecureChannel *channel, const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) { const UA_SecurityPolicy *sp = channel->securityPolicy; - if(!UA_ByteString_equal(&sp->policyUri, &asymHeader->securityPolicyUri)) return UA_STATUSCODE_BADSECURITYPOLICYREJECTED; @@ -21781,7 +20049,7 @@ checkAsymHeader(UA_SecureChannel *channel, } UA_StatusCode -checkSymHeader(UA_SecureChannel *channel, UA_UInt32 tokenId) { +checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId) { /* If no match, try to revolve to the next token after a * RenewSecureChannel */ UA_StatusCode retval = UA_STATUSCODE_GOOD; @@ -21798,18 +20066,18 @@ checkSymHeader(UA_SecureChannel *channel, UA_UInt32 tokenId) { break; /* Not the new token */ - if(tokenId != channel->altSecurityToken.tokenId) { - UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, - "Unknown SecurityToken"); - return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; - } + UA_CHECK(tokenId == channel->altSecurityToken.tokenId, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Unknown SecurityToken"); + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN); /* Roll over to the new token, generate new local and remote keys */ channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; channel->securityToken = channel->altSecurityToken; UA_ChannelSecurityToken_init(&channel->altSecurityToken); - retval = UA_SecureChannel_generateLocalKeys(channel); + retval |= UA_SecureChannel_generateLocalKeys(channel); retval |= generateRemoteKeys(channel); + UA_CHECK_STATUS(retval, return retval); break; case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT: @@ -21820,11 +20088,10 @@ checkSymHeader(UA_SecureChannel *channel, UA_UInt32 tokenId) { } /* Not the new token */ - if(tokenId != channel->securityToken.tokenId) { - UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, - "Unknown SecurityToken"); - return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; - } + UA_CHECK(tokenId == channel->securityToken.tokenId, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Unknown SecurityToken"); + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN); /* The remote server uses the new token for the first time. Delete the * old token and roll the remote key over. The local key already uses @@ -21832,11 +20099,9 @@ checkSymHeader(UA_SecureChannel *channel, UA_UInt32 tokenId) { channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; UA_ChannelSecurityToken_init(&channel->altSecurityToken); retval = generateRemoteKeys(channel); + UA_CHECK_STATUS(retval, return retval); } - if(retval != UA_STATUSCODE_GOOD) - return retval; - UA_DateTime timeout = token->createdAt + (token->revisedLifetime * UA_DATETIME_MSEC); if(channel->state == UA_SECURECHANNELSTATE_OPEN && timeout < UA_DateTime_nowMonotonic()) { @@ -21849,27 +20114,7 @@ checkSymHeader(UA_SecureChannel *channel, UA_UInt32 tokenId) { return UA_STATUSCODE_GOOD; } -/* Functionality used by both the SecureChannel and the SecurityPolicy */ - -size_t -UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(const UA_SecurityPolicy *securityPolicy, - const void *channelContext, - size_t maxEncryptionLength) { - if(maxEncryptionLength == 0) - return 0; - - size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule. - encryptionAlgorithm.getRemotePlainTextBlockSize(securityPolicy, channelContext); - size_t encryptedBlockSize = securityPolicy->asymmetricModule.cryptoModule. - encryptionAlgorithm.getRemoteBlockSize(securityPolicy, channelContext); - if(plainTextBlockSize == 0) - return 0; - - size_t maxNumberOfBlocks = maxEncryptionLength / plainTextBlockSize; - return maxNumberOfBlocks * (encryptedBlockSize - plainTextBlockSize); -} - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_session.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_session.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -21890,17 +20135,32 @@ void UA_Session_init(UA_Session *session) { session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS; #ifdef UA_ENABLE_SUBSCRIPTIONS SIMPLEQ_INIT(&session->responseQueue); + TAILQ_INIT(&session->subscriptions); #endif } -void UA_Session_deleteMembersCleanup(UA_Session *session, UA_Server* server) { - UA_LOCK_ASSERT(server->serviceMutex, 1); +void UA_Session_clear(UA_Session *session, UA_Server* server) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + /* Remove all Subscriptions. This may send out remaining publish + * responses. */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_Subscription *sub, *tempsub; + TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) { + UA_Subscription_delete(server, sub); + } +#endif + +#ifdef UA_ENABLE_DIAGNOSTICS + deleteNode(server, session->sessionId, true); +#endif + UA_Session_detachFromSecureChannel(session); - UA_ApplicationDescription_deleteMembers(&session->clientDescription); - UA_NodeId_deleteMembers(&session->header.authenticationToken); - UA_NodeId_deleteMembers(&session->sessionId); - UA_String_deleteMembers(&session->sessionName); - UA_ByteString_deleteMembers(&session->serverNonce); + UA_ApplicationDescription_clear(&session->clientDescription); + UA_NodeId_clear(&session->header.authenticationToken); + UA_NodeId_clear(&session->sessionId); + UA_String_clear(&session->sessionName); + UA_ByteString_clear(&session->serverNonce); struct ContinuationPoint *cp, *next = session->continuationPoints; while((cp = next)) { next = ContinuationPoint_clear(cp); @@ -21908,12 +20168,28 @@ void UA_Session_deleteMembersCleanup(UA_Session *session, UA_Server* server) { } session->continuationPoints = NULL; session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS; + + UA_Array_delete(session->params, session->paramsSize, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + session->params = NULL; + session->paramsSize = 0; + + UA_Array_delete(session->localeIds, session->localeIdsSize, + &UA_TYPES[UA_TYPES_STRING]); + session->localeIds = NULL; + session->localeIdsSize = 0; + +#ifdef UA_ENABLE_DIAGNOSTICS + UA_SessionDiagnosticsDataType_clear(&session->diagnostics); + UA_SessionSecurityDiagnosticsDataType_clear(&session->securityDiagnostics); +#endif } void UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel) { UA_Session_detachFromSecureChannel(session); session->header.channel = channel; + session->header.serverSession = true; SLIST_INSERT_HEAD(&channel->sessions, &session->header, next); } @@ -21930,6 +20206,16 @@ UA_Session_detachFromSecureChannel(UA_Session *session) { SLIST_REMOVE(&channel->sessions, sh, UA_SessionHeader, next); break; } + + /* Clean up the response queue. Their RequestId is bound to the + * SecureChannel so they cannot be reused. */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_PublishResponseEntry *pre; + while((pre = UA_Session_dequeuePublishReq(session))) { + UA_PublishResponse_clear(&pre->response); + UA_free(pre); + } +#endif } UA_StatusCode @@ -21940,7 +20226,7 @@ UA_Session_generateNonce(UA_Session *session) { /* Is the length of the previous nonce correct? */ if(session->serverNonce.length != UA_SESSION_NONCELENTH) { - UA_ByteString_deleteMembers(&session->serverNonce); + UA_ByteString_clear(&session->serverNonce); UA_StatusCode retval = UA_ByteString_allocBuffer(&session->serverNonce, UA_SESSION_NONCELENTH); if(retval != UA_STATUSCODE_GOOD) @@ -21948,54 +20234,91 @@ UA_Session_generateNonce(UA_Session *session) { } return channel->securityPolicy->symmetricModule. - generateNonce(channel->securityPolicy, &session->serverNonce); + generateNonce(channel->securityPolicy->policyContext, &session->serverNonce); } void UA_Session_updateLifetime(UA_Session *session) { session->validTill = UA_DateTime_nowMonotonic() + (UA_DateTime)(session->timeout * UA_DATETIME_MSEC); +#ifdef UA_ENABLE_DIAGNOSTICS + session->diagnostics.clientLastContactTime = UA_DateTime_now(); +#endif } #ifdef UA_ENABLE_SUBSCRIPTIONS -void UA_Session_addSubscription(UA_Server *server, UA_Session *session, UA_Subscription *newSubscription) { - newSubscription->subscriptionId = ++session->lastSubscriptionId; - - LIST_INSERT_HEAD(&session->serverSubscriptions, newSubscription, listEntry); - session->numSubscriptions++; - server->numSubscriptions++; +void +UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub) { + /* Attach to the session */ + sub->session = session; + + /* Increase the count */ + session->subscriptionsSize++; + + /* Increase the number of outstanding retransmissions */ + session->totalRetransmissionQueueSize += sub->retransmissionQueueSize; + + /* Insert at the end of the subscriptions of the same priority / just before + * the subscriptions with the next lower priority. */ + UA_Subscription *after = NULL; + TAILQ_FOREACH(after, &session->subscriptions, sessionListEntry) { + if(after->priority < sub->priority) { + TAILQ_INSERT_BEFORE(after, sub, sessionListEntry); + return; + } + } + TAILQ_INSERT_TAIL(&session->subscriptions, sub, sessionListEntry); } -UA_StatusCode -UA_Session_deleteSubscription(UA_Server *server, UA_Session *session, - UA_UInt32 subscriptionId) { - UA_LOCK_ASSERT(server->serviceMutex, 1); - - UA_Subscription *sub = UA_Session_getSubscriptionById(session, subscriptionId); - if(!sub) - return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; - - UA_Subscription_deleteMembers(server, sub); - - /* Add a delayed callback to remove the subscription when the currently - * scheduled jobs have completed. There is no actual delayed callback. Just - * free the structure. */ - sub->delayedFreePointers.callback = NULL; - UA_WorkQueue_enqueueDelayed(&server->workQueue, &sub->delayedFreePointers); - - /* Remove from the session */ - LIST_REMOVE(sub, listEntry); - UA_assert(session->numSubscriptions > 0); - UA_assert(server->numSubscriptions > 0); - session->numSubscriptions--; - server->numSubscriptions--; - return UA_STATUSCODE_GOOD; +void +UA_Session_detachSubscription(UA_Server *server, UA_Session *session, + UA_Subscription *sub, UA_Boolean releasePublishResponses) { + /* Detach from the session */ + sub->session = NULL; + TAILQ_REMOVE(&session->subscriptions, sub, sessionListEntry); + + /* Reduce the count */ + UA_assert(session->subscriptionsSize > 0); + session->subscriptionsSize--; + + /* Reduce the number of outstanding retransmissions */ + session->totalRetransmissionQueueSize -= sub->retransmissionQueueSize; + + /* Send remaining publish responses if the last subscription was removed */ + if(!releasePublishResponses || !TAILQ_EMPTY(&session->subscriptions)) + return; + UA_PublishResponseEntry *pre; + while((pre = UA_Session_dequeuePublishReq(session))) { + UA_PublishResponse *response = &pre->response; + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION; + response->responseHeader.timestamp = UA_DateTime_now(); + sendResponse(server, session, session->header.channel, pre->requestId, + (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + UA_PublishResponse_clear(response); + UA_free(pre); + } } UA_Subscription * UA_Session_getSubscriptionById(UA_Session *session, UA_UInt32 subscriptionId) { UA_Subscription *sub; - LIST_FOREACH(sub, &session->serverSubscriptions, listEntry) { + TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) { + /* Prevent lookup of subscriptions that are to be deleted with a statuschange */ + if(sub->statusChange != UA_STATUSCODE_GOOD) + continue; + if(sub->subscriptionId == subscriptionId) + break; + } + return sub; +} + +UA_Subscription * +UA_Server_getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId) { + UA_Subscription *sub; + LIST_FOREACH(sub, &server->subscriptions, serverListEntry) { + /* Prevent lookup of subscriptions that are to be deleted with a statuschange */ + if(sub->statusChange != UA_STATUSCODE_GOOD) + continue; if(sub->subscriptionId == subscriptionId) break; } @@ -22007,29 +20330,154 @@ UA_Session_dequeuePublishReq(UA_Session *session) { UA_PublishResponseEntry* entry = SIMPLEQ_FIRST(&session->responseQueue); if(entry) { SIMPLEQ_REMOVE_HEAD(&session->responseQueue, listEntry); - session->numPublishReq--; + session->responseQueueSize--; } return entry; } void -UA_Session_queuePublishReq(UA_Session *session, UA_PublishResponseEntry* entry, UA_Boolean head) { +UA_Session_queuePublishReq(UA_Session *session, UA_PublishResponseEntry* entry, + UA_Boolean head) { if(!head) SIMPLEQ_INSERT_TAIL(&session->responseQueue, entry, listEntry); else SIMPLEQ_INSERT_HEAD(&session->responseQueue, entry, listEntry); - session->numPublishReq++; + session->responseQueueSize++; } #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_nodes.c" ***********************************/ +/* Session Handling */ + +UA_StatusCode +UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId) { + UA_LOCK(&server->serviceMutex); + session_list_entry *entry; + UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID; + LIST_FOREACH(entry, &server->sessions, pointers) { + if(UA_NodeId_equal(&entry->session.sessionId, sessionId)) { + UA_Server_removeSession(server, entry, UA_DIAGNOSTICEVENT_CLOSE); + res = UA_STATUSCODE_GOOD; + break; + } + } + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_setSessionParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, const UA_Variant *parameter) { + UA_LOCK(&server->serviceMutex); + UA_Session *session = UA_Server_getSessionById(server, sessionId); + UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID; + if(session) + res = UA_KeyValueMap_set(&session->params, &session->paramsSize, + name, parameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +void +UA_Server_deleteSessionParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name) { + UA_LOCK(&server->serviceMutex); + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(session) + UA_KeyValueMap_delete(&session->params, &session->paramsSize, name); + UA_UNLOCK(&server->serviceMutex); +} + +UA_StatusCode +UA_Server_getSessionParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, UA_Variant *outParameter) { + UA_LOCK(&server->serviceMutex); + if(!outParameter) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSESSIONIDINVALID; + } + + const UA_Variant *param = + UA_KeyValueMap_get(session->params, session->paramsSize, name); + if(!param) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_StatusCode res = UA_Variant_copy(param, outParameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_getSessionScalarParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, const UA_DataType *type, + UA_Variant *outParameter) { + UA_LOCK(&server->serviceMutex); + if(!outParameter) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSESSIONIDINVALID; + } + + const UA_Variant *param = + UA_KeyValueMap_get(session->params, session->paramsSize, name); + if(!param || !UA_Variant_hasScalarType(param, type)) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_StatusCode res = UA_Variant_copy(param, outParameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_getSessionArrayParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, const UA_DataType *type, + UA_Variant *outParameter) { + UA_LOCK(&server->serviceMutex); + if(!outParameter) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSESSIONIDINVALID; + } + + const UA_Variant *param = + UA_KeyValueMap_get(session->params, session->paramsSize, name); + if(!param || !UA_Variant_hasArrayType(param, type)) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_StatusCode res = UA_Variant_copy(param, outParameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +/**** amalgamated original file "/src/server/ua_nodes.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2015-2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2015-2016 (c) Sten Grüner * Copyright 2015 (c) Chris Iatrou * Copyright 2015, 2017 (c) Florian Palm @@ -22039,53 +20487,373 @@ UA_Session_queuePublishReq(UA_Session *session, UA_PublishResponseEntry* entry, */ -/* ZipTree for the lookup of references by their identifier */ +/*****************/ +/* Node Pointers */ +/*****************/ -static enum ZIP_CMP +#define UA_NODEPOINTER_MASK 0x03 +#define UA_NODEPOINTER_TAG_IMMEDIATE 0x00 +#define UA_NODEPOINTER_TAG_NODEID 0x01 +#define UA_NODEPOINTER_TAG_EXPANDEDNODEID 0x02 +#define UA_NODEPOINTER_TAG_NODE 0x03 + +void +UA_NodePointer_clear(UA_NodePointer *np) { + switch(np->immediate & UA_NODEPOINTER_MASK) { + case UA_NODEPOINTER_TAG_NODEID: + np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + UA_NodeId_delete((UA_NodeId*)(uintptr_t)np->id); + break; + case UA_NODEPOINTER_TAG_EXPANDEDNODEID: + np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + UA_ExpandedNodeId_delete((UA_ExpandedNodeId*)(uintptr_t) + np->expandedId); + break; + default: + break; + } + UA_NodePointer_init(np); +} + +UA_StatusCode +UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_Byte tag = in.immediate & UA_NODEPOINTER_MASK; + in.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + switch(tag) { + case UA_NODEPOINTER_TAG_NODE: + in.id = &in.node->nodeId; + goto nodeid; /* fallthrough */ + case UA_NODEPOINTER_TAG_NODEID: + nodeid: + out->id = UA_NodeId_new(); + if(!out->id) + return UA_STATUSCODE_BADOUTOFMEMORY; + res = UA_NodeId_copy(in.id, (UA_NodeId*)(uintptr_t)out->id); + if(res != UA_STATUSCODE_GOOD) { + UA_free((void*)out->immediate); + out->immediate = 0; + break; + } + out->immediate |= UA_NODEPOINTER_TAG_NODEID; + break; + case UA_NODEPOINTER_TAG_EXPANDEDNODEID: + out->expandedId = UA_ExpandedNodeId_new(); + if(!out->expandedId) + return UA_STATUSCODE_BADOUTOFMEMORY; + res = UA_ExpandedNodeId_copy(in.expandedId, + (UA_ExpandedNodeId*)(uintptr_t) + out->expandedId); + if(res != UA_STATUSCODE_GOOD) { + UA_free((void*)out->immediate); + out->immediate = 0; + break; + } + out->immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID; + break; + default: + case UA_NODEPOINTER_TAG_IMMEDIATE: + *out = in; + break; + } + return res; +} + +UA_Boolean +UA_NodePointer_isLocal(UA_NodePointer np) { + UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK; + return (tag != UA_NODEPOINTER_TAG_EXPANDEDNODEID); +} + +UA_Order +UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2) { + if(p1.immediate == p2.immediate) + return UA_ORDER_EQ; + + /* Extract the tag and resolve pointers to nodes */ + UA_Byte tag1 = p1.immediate & UA_NODEPOINTER_MASK; + if(tag1 == UA_NODEPOINTER_TAG_NODE) { + p1 = UA_NodePointer_fromNodeId(&p1.node->nodeId); + tag1 = p1.immediate & UA_NODEPOINTER_MASK; + } + UA_Byte tag2 = p2.immediate & UA_NODEPOINTER_MASK; + if(tag2 == UA_NODEPOINTER_TAG_NODE) { + p2 = UA_NodePointer_fromNodeId(&p2.node->nodeId); + tag2 = p2.immediate & UA_NODEPOINTER_MASK; + } + + /* Different tags, cannot be identical */ + if(tag1 != tag2) + return (tag1 > tag2) ? UA_ORDER_MORE : UA_ORDER_LESS; + + /* Immediate */ + if(UA_LIKELY(tag1 == UA_NODEPOINTER_TAG_IMMEDIATE)) + return (p1.immediate > p2.immediate) ? + UA_ORDER_MORE : UA_ORDER_LESS; + + /* Compare from pointers */ + p1.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + p2.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + if(tag1 == UA_NODEPOINTER_TAG_EXPANDEDNODEID) + return UA_ExpandedNodeId_order(p1.expandedId, p2.expandedId); + return UA_NodeId_order(p1.id, p2.id); +} + +UA_NodePointer +UA_NodePointer_fromNodeId(const UA_NodeId *id) { + UA_NodePointer np; + if(id->identifierType != UA_NODEIDTYPE_NUMERIC) { + np.id = id; + np.immediate |= UA_NODEPOINTER_TAG_NODEID; + return np; + } + +#if SIZE_MAX > UA_UINT32_MAX + /* 64bit: 4 Byte for the numeric identifier + 2 Byte for the namespaceIndex + * + 1 Byte for the tagging bit (zero) */ + np.immediate = ((uintptr_t)id->identifier.numeric) << 32; + np.immediate |= ((uintptr_t)id->namespaceIndex) << 8; +#else + /* 32bit: 3 Byte for the numeric identifier + 6 Bit for the namespaceIndex + * + 2 Bit for the tagging bit (zero) */ + if(id->namespaceIndex < (0x01 << 6) && + id->identifier.numeric < (0x01 << 24)) { + np.immediate = ((uintptr_t)id->identifier.numeric) << 8; + np.immediate |= ((uintptr_t)id->namespaceIndex) << 2; + } else { + np.id = id; + np.immediate |= UA_NODEPOINTER_TAG_NODEID; + } +#endif + return np; +} + +UA_NodeId +UA_NodePointer_toNodeId(UA_NodePointer np) { + UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK; + np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + switch(tag) { + case UA_NODEPOINTER_TAG_NODE: + return np.node->nodeId; + case UA_NODEPOINTER_TAG_NODEID: + return *np.id; + case UA_NODEPOINTER_TAG_EXPANDEDNODEID: + return np.expandedId->nodeId; + default: + case UA_NODEPOINTER_TAG_IMMEDIATE: + break; + } + + UA_NodeId id; + id.identifierType = UA_NODEIDTYPE_NUMERIC; +#if SIZE_MAX > UA_UINT32_MAX /* 64bit */ + id.namespaceIndex = (UA_UInt16)(np.immediate >> 8); + id.identifier.numeric = (UA_UInt32)(np.immediate >> 32); +#else /* 32bit */ + id.namespaceIndex = ((UA_Byte)np.immediate) >> 2; + id.identifier.numeric = np.immediate >> 8; +#endif + return id; +} + +UA_NodePointer +UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id) { + if(!UA_ExpandedNodeId_isLocal(id)) { + UA_NodePointer np; + np.expandedId = id; + np.immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID; + return np; + } + return UA_NodePointer_fromNodeId(&id->nodeId); +} + +UA_ExpandedNodeId +UA_NodePointer_toExpandedNodeId(UA_NodePointer np) { + /* Resolve node pointer to get the NodeId */ + UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK; + if(tag == UA_NODEPOINTER_TAG_NODE) { + np = UA_NodePointer_fromNodeId(&np.node->nodeId); + tag = np.immediate & UA_NODEPOINTER_MASK; + } + + /* ExpandedNodeId, make a shallow copy */ + if(tag == UA_NODEPOINTER_TAG_EXPANDEDNODEID) { + np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + return *np.expandedId; + } + + /* NodeId, either immediate or via a pointer */ + UA_ExpandedNodeId en; + UA_ExpandedNodeId_init(&en); + en.nodeId = UA_NodePointer_toNodeId(np); + return en; +} + +/**************/ +/* References */ +/**************/ + +static UA_StatusCode +addReferenceTarget(UA_NodeReferenceKind *refs, UA_NodePointer target, + UA_UInt32 targetNameHash); + +static enum aa_cmp cmpRefTargetId(const void *a, const void *b) { - const UA_ReferenceTarget *aa = (const UA_ReferenceTarget*)a; - const UA_ReferenceTarget *bb = (const UA_ReferenceTarget*)b; + const UA_ReferenceTargetTreeElem *aa = (const UA_ReferenceTargetTreeElem*)a; + const UA_ReferenceTargetTreeElem *bb = (const UA_ReferenceTargetTreeElem*)b; if(aa->targetIdHash < bb->targetIdHash) - return ZIP_CMP_LESS; + return AA_CMP_LESS; if(aa->targetIdHash > bb->targetIdHash) - return ZIP_CMP_MORE; - return (enum ZIP_CMP)UA_ExpandedNodeId_order(&aa->targetId, &bb->targetId); + return AA_CMP_MORE; + return (enum aa_cmp)UA_NodePointer_order(aa->target.targetId, + bb->target.targetId); } -ZIP_IMPL(UA_ReferenceTargetIdTree, UA_ReferenceTarget, idTreeFields, - UA_ReferenceTarget, idTreeFields, cmpRefTargetId) - -/* ZipTree for the lookup of references by their BrowseName. UA_ReferenceTarget - * stores only the hash. A full node lookup is in order to do the actual - * comparison. */ - -static enum ZIP_CMP -cmpRefTargetName(const UA_UInt32 *nameHashA, const UA_UInt32 *nameHashB) { +static enum aa_cmp +cmpRefTargetName(const void *a, const void *b) { + const UA_UInt32 *nameHashA = (const UA_UInt32*)a; + const UA_UInt32 *nameHashB = (const UA_UInt32*)b; if(*nameHashA < *nameHashB) - return ZIP_CMP_LESS; + return AA_CMP_LESS; if(*nameHashA > *nameHashB) - return ZIP_CMP_MORE; - return ZIP_CMP_EQ; + return AA_CMP_MORE; + return AA_CMP_EQ; +} + +/* Reusable binary search tree "heads". Just switch out the root pointer. */ +static const struct aa_head refIdTree = + { NULL, cmpRefTargetId, offsetof(UA_ReferenceTargetTreeElem, idTreeEntry), 0 }; +const struct aa_head refNameTree = + { NULL, cmpRefTargetName, offsetof(UA_ReferenceTargetTreeElem, nameTreeEntry), + offsetof(UA_ReferenceTarget, targetNameHash) }; + +const UA_ReferenceTarget * +UA_NodeReferenceKind_iterate(const UA_NodeReferenceKind *rk, + const UA_ReferenceTarget *prev) { + /* Return from the tree */ + if(rk->hasRefTree) { + const struct aa_head _refIdTree = + { rk->targets.tree.idTreeRoot, cmpRefTargetId, + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry), 0 }; + if(prev == NULL) + return (const UA_ReferenceTarget*)aa_min(&_refIdTree); + return (const UA_ReferenceTarget*)aa_next(&_refIdTree, prev); + } + if(prev == NULL) /* Return start of the array */ + return rk->targets.array; + if(prev + 1 >= &rk->targets.array[rk->targetsSize]) + return NULL; /* End of the array */ + return prev + 1; /* Next element in the array */ +} + +/* Also deletes the elements of the tree */ +static void +moveTreeToArray(UA_ReferenceTarget *array, size_t *pos, + struct aa_entry *entry) { + if(!entry) + return; + UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*) + ((uintptr_t)entry - offsetof(UA_ReferenceTargetTreeElem, idTreeEntry)); + moveTreeToArray(array, pos, elem->idTreeEntry.left); + moveTreeToArray(array, pos, elem->idTreeEntry.right); + array[*pos] = elem->target; + (*pos)++; + UA_free(elem); } -ZIP_IMPL(UA_ReferenceTargetNameTree, UA_ReferenceTarget, nameTreeFields, - UA_UInt32, targetNameHash, cmpRefTargetName) +UA_StatusCode +UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk) { + if(rk->hasRefTree) { + /* From tree to array */ + UA_ReferenceTarget *array = (UA_ReferenceTarget*) + UA_malloc(sizeof(UA_ReferenceTarget) * rk->targetsSize); + if(!array) + return UA_STATUSCODE_BADOUTOFMEMORY; + size_t pos = 0; + moveTreeToArray(array, &pos, rk->targets.tree.idTreeRoot); + rk->targets.array = array; + rk->hasRefTree = false; + return UA_STATUSCODE_GOOD; + } + + /* From array to tree */ + UA_NodeReferenceKind newRk = *rk; + newRk.hasRefTree = true; + newRk.targets.tree.idTreeRoot = NULL; + newRk.targets.tree.nameTreeRoot = NULL; + for(size_t i = 0; i < rk->targetsSize; i++) { + UA_StatusCode res = + addReferenceTarget(&newRk, rk->targets.array[i].targetId, + rk->targets.array[i].targetNameHash); + if(res != UA_STATUSCODE_GOOD) { + struct aa_head _refIdTree = refIdTree; + _refIdTree.root = newRk.targets.tree.idTreeRoot; + while(_refIdTree.root) { + UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*) + ((uintptr_t)_refIdTree.root - + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry)); + aa_remove(&_refIdTree, elem); + UA_NodePointer_clear(&elem->target.targetId); + UA_free(elem); + } + return res; + } + } + for(size_t i = 0; i < rk->targetsSize; i++) + UA_NodePointer_clear(&rk->targets.array[i].targetId); + UA_free(rk->targets.array); + *rk = newRk; + return UA_STATUSCODE_GOOD; +} + +const UA_ReferenceTarget * +UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk, + const UA_ExpandedNodeId *targetId) { + UA_NodePointer targetP = UA_NodePointer_fromExpandedNodeId(targetId); + + /* Return from the tree */ + if(rk->hasRefTree) { + UA_ReferenceTargetTreeElem tmpTarget; + tmpTarget.target.targetId = targetP; + tmpTarget.targetIdHash = UA_ExpandedNodeId_hash(targetId); + const struct aa_head _refIdTree = + { rk->targets.tree.idTreeRoot, cmpRefTargetId, + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry), 0 }; + return (const UA_ReferenceTarget*)aa_find(&_refIdTree, &tmpTarget); + } + + /* Return from the array */ + for(size_t i = 0; i < rk->targetsSize; i++) { + if(UA_NodePointer_equal(targetP, rk->targets.array[i].targetId)) + return &rk->targets.array[i]; + } + return NULL; +} + +const UA_Node * +UA_NODESTORE_GETFROMREF(UA_Server *server, UA_NodePointer target) { + if(!UA_NodePointer_isLocal(target)) + return NULL; + UA_NodeId id = UA_NodePointer_toNodeId(target); + return UA_NODESTORE_GET(server, &id); +} /* General node handling methods. There is no UA_Node_new() method here. * Creating nodes is part of the Nodestore layer */ void UA_Node_clear(UA_Node *node) { - /* Delete standard content */ - UA_NodeId_clear(&node->nodeId); - UA_QualifiedName_clear(&node->browseName); - UA_LocalizedText_clear(&node->displayName); - UA_LocalizedText_clear(&node->description); - /* Delete references */ UA_Node_deleteReferences(node); + /* Delete other head content */ + UA_NodeHead *head = &node->head; + UA_NodeId_clear(&head->nodeId); + UA_QualifiedName_clear(&head->browseName); + UA_LocalizedText_clear(&head->displayName); + UA_LocalizedText_clear(&head->description); + /* Delete unique content of the nodeclass */ - switch(node->nodeClass) { + switch(head->nodeClass) { case UA_NODECLASS_OBJECT: break; case UA_NODECLASS_METHOD: @@ -22094,7 +20862,7 @@ void UA_Node_clear(UA_Node *node) { break; case UA_NODECLASS_VARIABLE: case UA_NODECLASS_VARIABLETYPE: { - UA_VariableNode *p = (UA_VariableNode*)node; + UA_VariableNode *p = &node->variableNode; UA_NodeId_clear(&p->dataType); UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]); @@ -22105,7 +20873,7 @@ void UA_Node_clear(UA_Node *node) { break; } case UA_NODECLASS_REFERENCETYPE: { - UA_ReferenceTypeNode *p = (UA_ReferenceTypeNode*)node; + UA_ReferenceTypeNode *p = &node->referenceTypeNode; UA_LocalizedText_clear(&p->inverseName); break; } @@ -22126,10 +20894,9 @@ UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) { static UA_StatusCode UA_CommonVariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) { - UA_StatusCode retval = UA_Array_copy(src->arrayDimensions, - src->arrayDimensionsSize, - (void**)&dst->arrayDimensions, - &UA_TYPES[UA_TYPES_INT32]); + UA_StatusCode retval = + UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize, + (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]); if(retval != UA_STATUSCODE_GOOD) return retval; dst->arrayDimensionsSize = src->arrayDimensionsSize; @@ -22147,20 +20914,18 @@ UA_CommonVariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) { static UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) { - UA_StatusCode retval = UA_CommonVariableNode_copy(src, dst); dst->accessLevel = src->accessLevel; dst->minimumSamplingInterval = src->minimumSamplingInterval; dst->historizing = src->historizing; - return retval; + dst->isDynamic = src->isDynamic; + return UA_CommonVariableNode_copy(src, dst); } static UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) { - UA_StatusCode retval = UA_CommonVariableNode_copy((const UA_VariableNode*)src, - (UA_VariableNode*)dst); dst->isAbstract = src->isAbstract; - return retval; + return UA_CommonVariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst); } static UA_StatusCode @@ -22183,11 +20948,11 @@ UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) { static UA_StatusCode UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_ReferenceTypeNode *dst) { - UA_StatusCode retval = UA_LocalizedText_copy(&src->inverseName, - &dst->inverseName); dst->isAbstract = src->isAbstract; dst->symmetric = src->symmetric; - return retval; + dst->referenceTypeIndex = src->referenceTypeIndex; + dst->subTypes = src->subTypes; + return UA_LocalizedText_copy(&src->inverseName, &dst->inverseName); } static UA_StatusCode @@ -22205,121 +20970,82 @@ UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) { UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) { - if(src->nodeClass != dst->nodeClass) + const UA_NodeHead *srchead = &src->head; + UA_NodeHead *dsthead = &dst->head; + if(srchead->nodeClass != dsthead->nodeClass) return UA_STATUSCODE_BADINTERNALERROR; /* Copy standard content */ - UA_StatusCode retval = UA_NodeId_copy(&src->nodeId, &dst->nodeId); - retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName); - retval |= UA_LocalizedText_copy(&src->displayName, &dst->displayName); - retval |= UA_LocalizedText_copy(&src->description, &dst->description); - dst->writeMask = src->writeMask; - dst->context = src->context; - dst->constructed = src->constructed; + UA_StatusCode retval = UA_NodeId_copy(&srchead->nodeId, &dsthead->nodeId); + retval |= UA_QualifiedName_copy(&srchead->browseName, &dsthead->browseName); + retval |= UA_LocalizedText_copy(&srchead->displayName, &dsthead->displayName); + retval |= UA_LocalizedText_copy(&srchead->description, &dsthead->description); + dsthead->writeMask = srchead->writeMask; + dsthead->context = srchead->context; + dsthead->constructed = srchead->constructed; +#ifdef UA_ENABLE_SUBSCRIPTIONS + dsthead->monitoredItems = srchead->monitoredItems; +#endif if(retval != UA_STATUSCODE_GOOD) { UA_Node_clear(dst); return retval; } /* Copy the references */ - dst->references = NULL; - if(src->referencesSize > 0) { - dst->references = (UA_NodeReferenceKind*) - UA_calloc(src->referencesSize, sizeof(UA_NodeReferenceKind)); - if(!dst->references) { + dsthead->references = NULL; + if(srchead->referencesSize > 0) { + dsthead->references = (UA_NodeReferenceKind*) + UA_calloc(srchead->referencesSize, sizeof(UA_NodeReferenceKind)); + if(!dsthead->references) { UA_Node_clear(dst); return UA_STATUSCODE_BADOUTOFMEMORY; } - dst->referencesSize = src->referencesSize; + dsthead->referencesSize = srchead->referencesSize; - for(size_t i = 0; i < src->referencesSize; ++i) { - UA_NodeReferenceKind *srefs = &src->references[i]; - UA_NodeReferenceKind *drefs = &dst->references[i]; + for(size_t i = 0; i < srchead->referencesSize; ++i) { + UA_NodeReferenceKind *srefs = &srchead->references[i]; + UA_NodeReferenceKind *drefs = &dsthead->references[i]; + drefs->referenceTypeIndex = srefs->referenceTypeIndex; drefs->isInverse = srefs->isInverse; - ZIP_INIT(&drefs->refTargetsIdTree); - retval = UA_NodeId_copy(&srefs->referenceTypeId, &drefs->referenceTypeId); - if(retval != UA_STATUSCODE_GOOD) - break; - drefs->refTargets = (UA_ReferenceTarget*) - UA_malloc(srefs->refTargetsSize* sizeof(UA_ReferenceTarget)); - if(!drefs->refTargets) { - UA_NodeId_clear(&drefs->referenceTypeId); - break; - } - uintptr_t arraydiff = (uintptr_t)drefs->refTargets - (uintptr_t)srefs->refTargets; - for(size_t j = 0; j < srefs->refTargetsSize; j++) { - UA_ReferenceTarget *srefTarget = &srefs->refTargets[j]; - UA_ReferenceTarget *drefTarget = &drefs->refTargets[j]; - retval |= UA_ExpandedNodeId_copy(&srefTarget->targetId, &drefTarget->targetId); - drefTarget->targetIdHash = srefTarget->targetIdHash; - drefTarget->targetNameHash = srefTarget->targetNameHash; - ZIP_RANK(drefTarget, idTreeFields) = ZIP_RANK(srefTarget, idTreeFields); - /* IdTree Fields */ - ZIP_RIGHT(drefTarget, idTreeFields) = NULL; - if(ZIP_RIGHT(srefTarget, idTreeFields)) - ZIP_RIGHT(drefTarget, idTreeFields) = (UA_ReferenceTarget*) - ((uintptr_t)ZIP_RIGHT(srefTarget, idTreeFields) + arraydiff); - ZIP_LEFT(drefTarget, idTreeFields) = NULL; - if(ZIP_LEFT(srefTarget, idTreeFields)) - ZIP_LEFT(drefTarget, idTreeFields) = (UA_ReferenceTarget*) - ((uintptr_t)ZIP_LEFT(srefTarget, idTreeFields) + arraydiff); - /* NameTree Fields */ - ZIP_RIGHT(drefTarget, nameTreeFields) = NULL; - if(ZIP_RIGHT(srefTarget, nameTreeFields)) - ZIP_RIGHT(drefTarget, nameTreeFields) = (UA_ReferenceTarget*) - ((uintptr_t)ZIP_RIGHT(srefTarget, nameTreeFields) + arraydiff); - ZIP_LEFT(drefTarget, nameTreeFields) = NULL; - if(ZIP_LEFT(srefTarget, nameTreeFields)) - ZIP_LEFT(drefTarget, nameTreeFields) = (UA_ReferenceTarget*) - ((uintptr_t)ZIP_LEFT(srefTarget, nameTreeFields) + arraydiff); - } - /* IdTree Root */ - ZIP_ROOT(&drefs->refTargetsIdTree) = NULL; - if(ZIP_ROOT(&srefs->refTargetsIdTree)) - ZIP_ROOT(&drefs->refTargetsIdTree) = (UA_ReferenceTarget*) - ((uintptr_t)ZIP_ROOT(&srefs->refTargetsIdTree) + arraydiff); - /* NameTree Root */ - ZIP_ROOT(&drefs->refTargetsNameTree) = NULL; - if(ZIP_ROOT(&srefs->refTargetsNameTree)) - ZIP_ROOT(&drefs->refTargetsNameTree) = (UA_ReferenceTarget*) - ((uintptr_t)ZIP_ROOT(&srefs->refTargetsNameTree) + arraydiff); - - drefs->refTargetsSize = srefs->refTargetsSize; - if(retval != UA_STATUSCODE_GOOD) - break; - } + drefs->hasRefTree = srefs->hasRefTree; /* initially empty */ - if(retval != UA_STATUSCODE_GOOD) { - UA_Node_clear(dst); - return retval; + /* Copy all the targets */ + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(srefs, t))) { + retval = addReferenceTarget(drefs, t->targetId, t->targetNameHash); + if(retval != UA_STATUSCODE_GOOD) { + UA_Node_clear(dst); + return retval; + } + } } } /* Copy unique content of the nodeclass */ - switch(src->nodeClass) { + switch(src->head.nodeClass) { case UA_NODECLASS_OBJECT: - retval = UA_ObjectNode_copy((const UA_ObjectNode*)src, (UA_ObjectNode*)dst); + retval = UA_ObjectNode_copy(&src->objectNode, &dst->objectNode); break; case UA_NODECLASS_VARIABLE: - retval = UA_VariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst); + retval = UA_VariableNode_copy(&src->variableNode, &dst->variableNode); break; case UA_NODECLASS_METHOD: - retval = UA_MethodNode_copy((const UA_MethodNode*)src, (UA_MethodNode*)dst); + retval = UA_MethodNode_copy(&src->methodNode, &dst->methodNode); break; case UA_NODECLASS_OBJECTTYPE: - retval = UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)src, (UA_ObjectTypeNode*)dst); + retval = UA_ObjectTypeNode_copy(&src->objectTypeNode, &dst->objectTypeNode); break; case UA_NODECLASS_VARIABLETYPE: - retval = UA_VariableTypeNode_copy((const UA_VariableTypeNode*)src, (UA_VariableTypeNode*)dst); + retval = UA_VariableTypeNode_copy(&src->variableTypeNode, &dst->variableTypeNode); break; case UA_NODECLASS_REFERENCETYPE: - retval = UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)src, (UA_ReferenceTypeNode*)dst); + retval = UA_ReferenceTypeNode_copy(&src->referenceTypeNode, &dst->referenceTypeNode); break; case UA_NODECLASS_DATATYPE: - retval = UA_DataTypeNode_copy((const UA_DataTypeNode*)src, (UA_DataTypeNode*)dst); + retval = UA_DataTypeNode_copy(&src->dataTypeNode, &dst->dataTypeNode); break; case UA_NODECLASS_VIEW: - retval = UA_ViewNode_copy((const UA_ViewNode*)src, (UA_ViewNode*)dst); + retval = UA_ViewNode_copy(&src->viewNode, &dst->viewNode); break; default: break; @@ -22333,9 +21059,8 @@ UA_Node_copy(const UA_Node *src, UA_Node *dst) { UA_Node * UA_Node_copy_alloc(const UA_Node *src) { - /* use dstPtr to trick static code analysis in accepting dirty cast */ size_t nodesize = 0; - switch(src->nodeClass) { + switch(src->head.nodeClass) { case UA_NODECLASS_OBJECT: nodesize = sizeof(UA_ObjectNode); break; @@ -22364,11 +21089,11 @@ UA_Node_copy_alloc(const UA_Node *src) { return NULL; } - UA_Node *dst = (UA_Node*)UA_calloc(1,nodesize); + UA_Node *dst = (UA_Node*)UA_calloc(1, nodesize); if(!dst) return NULL; - dst->nodeClass = src->nodeClass; + dst->head.nodeClass = src->head.nodeClass; UA_StatusCode retval = UA_Node_copy(src, dst); if(retval != UA_STATUSCODE_GOOD) { @@ -22382,24 +21107,19 @@ UA_Node_copy_alloc(const UA_Node *src) { /******************************/ static UA_StatusCode -copyStandardAttributes(UA_Node *node, const UA_NodeAttributes *attr) { - /* retval = UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); */ - /* retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName); */ - - UA_StatusCode retval; - /* The new nodeset format has optional display name. - * See https://github.com/open62541/open62541/issues/2627 - * If display name is NULL, then we take the name part of the browse name */ - if (attr->displayName.text.length == 0) { - retval = UA_String_copy(&node->browseName.name, - &node->displayName.text); - } else { - retval = UA_LocalizedText_copy(&attr->displayName, - &node->displayName); - retval |= UA_LocalizedText_copy(&attr->description, &node->description); - } - - node->writeMask = attr->writeMask; +copyStandardAttributes(UA_NodeHead *head, const UA_NodeAttributes *attr) { + /* UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); */ + /* UA_QualifiedName_copy(&item->browseName, &node->browseName); */ + + head->writeMask = attr->writeMask; + UA_StatusCode retval = UA_LocalizedText_copy(&attr->description, &head->description); + /* The new nodeset format has optional display names: + * https://github.com/open62541/open62541/issues/2627. If the display name + * is NULL, take the name part of the browse name */ + if(attr->displayName.text.length == 0) + retval |= UA_String_copy(&head->browseName.name, &head->displayName.text); + else + retval |= UA_LocalizedText_copy(&attr->displayName, &head->displayName); return retval; } @@ -22494,50 +21214,47 @@ copyMethodNodeAttributes(UA_MethodNode *mnode, } UA_StatusCode -UA_Node_setAttributes(UA_Node *node, const void *attributes, - const UA_DataType *attributeType) { +UA_Node_setAttributes(UA_Node *node, const void *attributes, const UA_DataType *attributeType) { /* Copy the attributes into the node */ UA_StatusCode retval = UA_STATUSCODE_GOOD; - switch(node->nodeClass) { + switch(node->head.nodeClass) { case UA_NODECLASS_OBJECT: CHECK_ATTRIBUTES(OBJECTATTRIBUTES); - retval = copyObjectNodeAttributes((UA_ObjectNode*)node, + retval = copyObjectNodeAttributes(&node->objectNode, (const UA_ObjectAttributes*)attributes); break; case UA_NODECLASS_VARIABLE: CHECK_ATTRIBUTES(VARIABLEATTRIBUTES); - retval = copyVariableNodeAttributes((UA_VariableNode*)node, + retval = copyVariableNodeAttributes(&node->variableNode, (const UA_VariableAttributes*)attributes); break; case UA_NODECLASS_OBJECTTYPE: CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES); - retval = copyObjectTypeNodeAttributes((UA_ObjectTypeNode*)node, + retval = copyObjectTypeNodeAttributes(&node->objectTypeNode, (const UA_ObjectTypeAttributes*)attributes); break; case UA_NODECLASS_VARIABLETYPE: CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES); - retval = copyVariableTypeNodeAttributes((UA_VariableTypeNode*)node, + retval = copyVariableTypeNodeAttributes(&node->variableTypeNode, (const UA_VariableTypeAttributes*)attributes); break; case UA_NODECLASS_REFERENCETYPE: CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES); - retval = copyReferenceTypeNodeAttributes((UA_ReferenceTypeNode*)node, + retval = copyReferenceTypeNodeAttributes(&node->referenceTypeNode, (const UA_ReferenceTypeAttributes*)attributes); break; case UA_NODECLASS_DATATYPE: CHECK_ATTRIBUTES(DATATYPEATTRIBUTES); - retval = copyDataTypeNodeAttributes((UA_DataTypeNode*)node, + retval = copyDataTypeNodeAttributes(&node->dataTypeNode, (const UA_DataTypeAttributes*)attributes); break; case UA_NODECLASS_VIEW: CHECK_ATTRIBUTES(VIEWATTRIBUTES); - retval = copyViewNodeAttributes((UA_ViewNode*)node, - (const UA_ViewAttributes*)attributes); + retval = copyViewNodeAttributes(&node->viewNode, (const UA_ViewAttributes*)attributes); break; case UA_NODECLASS_METHOD: CHECK_ATTRIBUTES(METHODATTRIBUTES); - retval = copyMethodNodeAttributes((UA_MethodNode*)node, - (const UA_MethodAttributes*)attributes); + retval = copyMethodNodeAttributes(&node->methodNode, (const UA_MethodAttributes*)attributes); break; case UA_NODECLASS_UNSPECIFIED: default: @@ -22545,7 +21262,7 @@ UA_Node_setAttributes(UA_Node *node, const void *attributes, } if(retval == UA_STATUSCODE_GOOD) - retval = copyStandardAttributes(node, (const UA_NodeAttributes*)attributes); + retval = copyStandardAttributes(&node->head, (const UA_NodeAttributes*)attributes); if(retval != UA_STATUSCODE_GOOD) UA_Node_clear(node); return retval; @@ -22555,253 +21272,270 @@ UA_Node_setAttributes(UA_Node *node, const void *attributes, /* Manage References */ /*********************/ - static UA_StatusCode -resizeReferenceTargets(UA_NodeReferenceKind *refs, size_t newSize) { - - UA_ReferenceTarget *targets = (UA_ReferenceTarget*) - UA_realloc(refs->refTargets, newSize * sizeof(UA_ReferenceTarget)); - if(!targets) - return UA_STATUSCODE_BADOUTOFMEMORY; - - /* Repair the pointers in the tree for the realloced array */ - uintptr_t arraydiff = (uintptr_t)targets - (uintptr_t)refs->refTargets; - if(arraydiff != 0) { - for(size_t i = 0; i < refs->refTargetsSize; i++) { - if(targets[i].idTreeFields.zip_left) - targets[i].idTreeFields.zip_left = (UA_ReferenceTarget*) - ((uintptr_t)targets[i].idTreeFields.zip_left + arraydiff); - if(targets[i].idTreeFields.zip_right) - targets[i].idTreeFields.zip_right = (UA_ReferenceTarget*) - ((uintptr_t)targets[i].idTreeFields.zip_right + arraydiff); - if(targets[i].nameTreeFields.zip_left) - targets[i].nameTreeFields.zip_left = (UA_ReferenceTarget*) - ((uintptr_t)targets[i].nameTreeFields.zip_left + arraydiff); - if(targets[i].nameTreeFields.zip_right) - targets[i].nameTreeFields.zip_right = (UA_ReferenceTarget*) - ((uintptr_t)targets[i].nameTreeFields.zip_right + arraydiff); - } - } - - if(refs->refTargetsIdTree.zip_root) - refs->refTargetsIdTree.zip_root = (UA_ReferenceTarget*) - ((uintptr_t)refs->refTargetsIdTree.zip_root + arraydiff); - if(refs->refTargetsNameTree.zip_root) - refs->refTargetsNameTree.zip_root = (UA_ReferenceTarget*) - ((uintptr_t)refs->refTargetsNameTree.zip_root + arraydiff); - refs->refTargets = targets; - return UA_STATUSCODE_GOOD; -} +addReferenceTarget(UA_NodeReferenceKind *rk, UA_NodePointer targetId, + UA_UInt32 targetNameHash) { + /* Insert into array */ + if(!rk->hasRefTree) { + UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*) + UA_realloc(rk->targets.array, + sizeof(UA_ReferenceTarget) * (rk->targetsSize + 1)); + if(!newRefs) + return UA_STATUSCODE_BADOUTOFMEMORY; + rk->targets.array = newRefs; + UA_StatusCode retval = + UA_NodePointer_copy(targetId, + &rk->targets.array[rk->targetsSize].targetId); + rk->targets.array[rk->targetsSize].targetNameHash = targetNameHash; + if(retval != UA_STATUSCODE_GOOD) { + if(rk->targetsSize == 0) { + UA_free(rk->targets.array); + rk->targets.array = NULL; + } + return retval; + } + rk->targetsSize++; + return UA_STATUSCODE_GOOD; + } -static UA_StatusCode -addReferenceTarget(UA_NodeReferenceKind *refs, const UA_ExpandedNodeId *target, - UA_UInt32 targetIdHash, UA_UInt32 targetNameHash) { - UA_StatusCode retval = resizeReferenceTargets(refs, refs->refTargetsSize + 1); - if(retval != UA_STATUSCODE_GOOD) - return retval; + /* Insert into tree */ + UA_ReferenceTargetTreeElem *entry = (UA_ReferenceTargetTreeElem*) + UA_malloc(sizeof(UA_ReferenceTargetTreeElem)); + if(!entry) + return UA_STATUSCODE_BADOUTOFMEMORY; - UA_ReferenceTarget *entry = &refs->refTargets[refs->refTargetsSize]; - retval = UA_ExpandedNodeId_copy(target, &entry->targetId); + UA_StatusCode retval = + UA_NodePointer_copy(targetId, &entry->target.targetId); if(retval != UA_STATUSCODE_GOOD) { - if(refs->refTargetsSize== 0) { - /* We had zero references before (realloc was a malloc) */ - UA_free(refs->refTargets); - refs->refTargets = NULL; - } + UA_free(entry); return retval; } - entry->targetIdHash = targetIdHash; - entry->targetNameHash = targetNameHash; - unsigned char rank = ZIP_FFS32(UA_UInt32_random()); - ZIP_INSERT(UA_ReferenceTargetIdTree, &refs->refTargetsIdTree, entry, rank); - ZIP_INSERT(UA_ReferenceTargetNameTree, &refs->refTargetsNameTree, entry, rank); - refs->refTargetsSize++; + /* <-- The point of no return --> */ + + UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(targetId); + entry->targetIdHash = UA_ExpandedNodeId_hash(&en); + entry->target.targetNameHash = targetNameHash; + + /* Insert to the id lookup binary search tree. Only the root is kept in refs + * to save space. */ + struct aa_head _refIdTree = refIdTree; + _refIdTree.root = rk->targets.tree.idTreeRoot; + aa_insert(&_refIdTree, entry); + rk->targets.tree.idTreeRoot = _refIdTree.root; + + /* Insert to the name lookup binary search tree */ + struct aa_head _refNameTree = refNameTree; + _refNameTree.root = rk->targets.tree.nameTreeRoot; + aa_insert(&_refNameTree, entry); + rk->targets.tree.nameTreeRoot = _refNameTree.root; + + rk->targetsSize++; + return UA_STATUSCODE_GOOD; } static UA_StatusCode -addReferenceKind(UA_Node *node, const UA_AddReferencesItem *item, - UA_UInt32 targetBrowseNameHash) { +addReferenceKind(UA_NodeHead *head, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_NodePointer target, UA_UInt32 targetBrowseNameHash) { UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*) - UA_realloc(node->references, sizeof(UA_NodeReferenceKind) * (node->referencesSize+1)); + UA_realloc(head->references, + sizeof(UA_NodeReferenceKind) * (head->referencesSize+1)); if(!refs) return UA_STATUSCODE_BADOUTOFMEMORY; - node->references = refs; + head->references = refs; - UA_StatusCode retval = UA_STATUSCODE_GOOD; - UA_NodeReferenceKind *newRef = &refs[node->referencesSize]; + UA_NodeReferenceKind *newRef = &refs[head->referencesSize]; memset(newRef, 0, sizeof(UA_NodeReferenceKind)); - ZIP_INIT(&newRef->refTargetsIdTree); - ZIP_INIT(&newRef->refTargetsNameTree); - newRef->isInverse = !item->isForward; - retval |= UA_NodeId_copy(&item->referenceTypeId, &newRef->referenceTypeId); - retval |= addReferenceTarget(newRef, &item->targetNodeId, - UA_ExpandedNodeId_hash(&item->targetNodeId), - targetBrowseNameHash); + newRef->referenceTypeIndex = refTypeIndex; + newRef->isInverse = !isForward; + UA_StatusCode retval = + addReferenceTarget(newRef, target, targetBrowseNameHash); if(retval != UA_STATUSCODE_GOOD) { - UA_NodeId_clear(&newRef->referenceTypeId); - if(node->referencesSize == 0) { - UA_free(node->references); - node->references = NULL; + if(head->referencesSize == 0) { + UA_free(head->references); + head->references = NULL; } return retval; } - node->referencesSize++; + head->referencesSize++; return UA_STATUSCODE_GOOD; } UA_StatusCode -UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item, +UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId, UA_UInt32 targetBrowseNameHash) { - /* Find the matching refkind */ - UA_NodeReferenceKind *existingRefs = NULL; - for(size_t i = 0; i < node->referencesSize; ++i) { - UA_NodeReferenceKind *refs = &node->references[i]; - if(refs->isInverse != item->isForward && - UA_NodeId_equal(&refs->referenceTypeId, &item->referenceTypeId)) { - existingRefs = refs; - break; - } - } + /* Find the matching reference kind */ + for(size_t i = 0; i < node->head.referencesSize; ++i) { + UA_NodeReferenceKind *refs = &node->head.references[i]; + + /* Reference direction does not match */ + if(refs->isInverse == isForward) + continue; + + /* Reference type does not match */ + if(refs->referenceTypeIndex != refTypeIndex) + continue; - if(!existingRefs) - return addReferenceKind(node, item, targetBrowseNameHash); + /* Does an identical reference already exist? */ + const UA_ReferenceTarget *found = + UA_NodeReferenceKind_findTarget(refs, targetNodeId); + if(found) + return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED; - UA_ReferenceTarget tmpTarget; - tmpTarget.targetId = item->targetNodeId; - tmpTarget.targetIdHash = UA_ExpandedNodeId_hash(&item->targetNodeId); - UA_ReferenceTarget *found = - ZIP_FIND(UA_ReferenceTargetIdTree, &existingRefs->refTargetsIdTree, &tmpTarget); - if(found) - return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED; + /* Add to existing ReferenceKind */ + return addReferenceTarget(refs, UA_NodePointer_fromExpandedNodeId(targetNodeId), + targetBrowseNameHash); + } + + /* Add new ReferenceKind for the target */ + return addReferenceKind(&node->head, refTypeIndex, isForward, + UA_NodePointer_fromExpandedNodeId(targetNodeId), + targetBrowseNameHash); - return addReferenceTarget(existingRefs, &item->targetNodeId, - tmpTarget.targetIdHash, targetBrowseNameHash); } UA_StatusCode -UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item) { - for(size_t i = node->referencesSize; i > 0; --i) { - UA_NodeReferenceKind *refs = &node->references[i-1]; - if(item->isForward == refs->isInverse) +UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId) { + struct aa_head _refIdTree = refIdTree; + struct aa_head _refNameTree = refNameTree; + + UA_NodeHead *head = &node->head; + for(size_t i = 0; i < head->referencesSize; i++) { + UA_NodeReferenceKind *refs = &head->references[i]; + if(isForward == refs->isInverse) continue; - if(!UA_NodeId_equal(&item->referenceTypeId, &refs->referenceTypeId)) + if(refTypeIndex != refs->referenceTypeIndex) continue; - for(size_t j = refs->refTargetsSize; j > 0; --j) { - UA_ReferenceTarget *target = &refs->refTargets[j-1]; - if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &target->targetId.nodeId)) - continue; - - /* Ok, delete the reference */ - ZIP_REMOVE(UA_ReferenceTargetIdTree, &refs->refTargetsIdTree, target); - ZIP_REMOVE(UA_ReferenceTargetNameTree, &refs->refTargetsNameTree, target); - UA_ExpandedNodeId_clear(&target->targetId); - refs->refTargetsSize--; - - if(refs->refTargetsSize > 0) { - /* At least one target remains in buffer */ - if(j-1 != refs->refTargetsSize) { - /* Move last entry into the entry from where reference was removed */ - ZIP_REMOVE(UA_ReferenceTargetIdTree, &refs->refTargetsIdTree, - &refs->refTargets[refs->refTargetsSize]); - ZIP_REMOVE(UA_ReferenceTargetNameTree, &refs->refTargetsNameTree, - &refs->refTargets[refs->refTargetsSize]); - *target = refs->refTargets[refs->refTargetsSize]; - ZIP_INSERT(UA_ReferenceTargetIdTree, &refs->refTargetsIdTree, - target, ZIP_RANK(target, idTreeFields)); - ZIP_INSERT(UA_ReferenceTargetNameTree, &refs->refTargetsNameTree, - target, ZIP_RANK(target, nameTreeFields)); - } - /* Shrink down allocated buffer, ignore failure */ - (void)resizeReferenceTargets(refs, refs->refTargetsSize); - return UA_STATUSCODE_GOOD; - } + /* Cast out the const qualifier (hack!) */ + UA_ReferenceTarget *target = (UA_ReferenceTarget*)(uintptr_t) + UA_NodeReferenceKind_findTarget(refs, targetNodeId); + if(!target) + continue; - /* No target for the ReferenceType remaining. Remove entry. */ - UA_free(refs->refTargets); - UA_NodeId_clear(&refs->referenceTypeId); - node->referencesSize--; - if(node->referencesSize > 0) { - if(i-1 != node->referencesSize) { - /* Move last array node into array node from where reference kind was removed */ - node->references[i-1] = node->references[node->referencesSize]; - } - /* And shrink down allocated buffer for one entry */ - UA_NodeReferenceKind *newRefs = (UA_NodeReferenceKind*) - UA_realloc(node->references, sizeof(UA_NodeReferenceKind) * node->referencesSize); - /* Ignore errors in case memory buffer could not be shrinked down */ - if(newRefs) { - node->references = newRefs; - } - return UA_STATUSCODE_GOOD; + /* Ok, delete the reference. Cannot fail */ + refs->targetsSize--; + + if(!refs->hasRefTree) { + /* Remove from array */ + UA_NodePointer_clear(&target->targetId); + + /* Elements remaining. Realloc. */ + if(refs->targetsSize > 0) { + if(target != &refs->targets.array[refs->targetsSize]) + *target = refs->targets.array[refs->targetsSize]; + UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*) + UA_realloc(refs->targets.array, + sizeof(UA_ReferenceTarget) * refs->targetsSize); + if(newRefs) + refs->targets.array = newRefs; + return UA_STATUSCODE_GOOD; /* Realloc allowed to fail */ } + /* Remove the last target. Remove the ReferenceKind below */ + UA_free(refs->targets.array); + } else { + /* Remove from the tree */ + _refIdTree.root = refs->targets.tree.idTreeRoot; + aa_remove(&_refIdTree, target); + refs->targets.tree.idTreeRoot = _refIdTree.root; + + _refNameTree.root = refs->targets.tree.nameTreeRoot; + aa_remove(&_refNameTree, target); + refs->targets.tree.nameTreeRoot = _refNameTree.root; + + UA_NodePointer_clear(&target->targetId); + UA_free(target); + if(refs->targets.tree.idTreeRoot) + return UA_STATUSCODE_GOOD; /* At least one target remains */ + } + + /* No targets remaining. Remove the ReferenceKind. */ + head->referencesSize--; + if(head->referencesSize > 0) { + /* No target for the ReferenceType remaining. Remove and shrink down + * allocated buffer. Ignore errors in case memory buffer could not + * be shrinked down. */ + if(i != head->referencesSize) + head->references[i] = head->references[node->head.referencesSize]; + UA_NodeReferenceKind *newRefs = (UA_NodeReferenceKind*) + UA_realloc(head->references, + sizeof(UA_NodeReferenceKind) * head->referencesSize); + if(newRefs) + head->references = newRefs; + } else { /* No remaining references of any ReferenceType */ - UA_free(node->references); - node->references = NULL; - return UA_STATUSCODE_GOOD; + UA_free(head->references); + head->references = NULL; } + return UA_STATUSCODE_GOOD; } return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED; } void -UA_Node_deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, - UA_NodeId* referencesSkip) { - /* Nothing to do */ - if(node->referencesSize == 0 || node->references == NULL) - return; - - for(size_t i = node->referencesSize; i > 0; --i) { - UA_NodeReferenceKind *refs = &node->references[i-1]; +UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet) { + UA_NodeHead *head = &node->head; + struct aa_head _refIdTree = refIdTree; + for(size_t i = 0; i < head->referencesSize; i++) { + /* Keep the references of this type? */ + UA_NodeReferenceKind *refs = &head->references[i]; + if(UA_ReferenceTypeSet_contains(keepSet, refs->referenceTypeIndex)) + continue; - /* Shall we keep the references of this type? */ - UA_Boolean skip = false; - for(size_t j = 0; j < referencesSkipSize; j++) { - if(UA_NodeId_equal(&refs->referenceTypeId, &referencesSkip[j])) { - skip = true; - break; + /* Remove all target entries. Don't remove entries from browseName tree. + * The entire ReferenceKind will be removed anyway. */ + if(!refs->hasRefTree) { + for(size_t j = 0; j < refs->targetsSize; j++) + UA_NodePointer_clear(&refs->targets.array[j].targetId); + UA_free(refs->targets.array); + } else { + _refIdTree.root = refs->targets.tree.idTreeRoot; + while(_refIdTree.root) { + UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*) + ((uintptr_t)_refIdTree.root - + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry)); + aa_remove(&_refIdTree, elem); + UA_NodePointer_clear(&elem->target.targetId); + UA_free(elem); } } - if(skip) - continue; - /* Remove references */ - for(size_t j = 0; j < refs->refTargetsSize; j++) - UA_ExpandedNodeId_clear(&refs->refTargets[j].targetId); - UA_free(refs->refTargets); - UA_NodeId_clear(&refs->referenceTypeId); - node->referencesSize--; - - /* Move last references-kind entry to this position */ - if(i-1 == node->referencesSize) /* Don't memcpy over the same position */ - continue; - node->references[i-1] = node->references[node->referencesSize]; + /* Move last references-kind entry to this position. Don't memcpy over + * the same position. Decrease i to repeat at this location. */ + head->referencesSize--; + if(i != head->referencesSize) { + head->references[i] = head->references[head->referencesSize]; + i--; + } } - if(node->referencesSize > 0) { - /* Realloc to save memory */ + if(head->referencesSize > 0) { + /* Realloc to save memory. Ignore if realloc fails. */ UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*) - UA_realloc(node->references, sizeof(UA_NodeReferenceKind) * node->referencesSize); - if(refs) /* Do nothing if realloc fails */ - node->references = refs; - return; + UA_realloc(head->references, + sizeof(UA_NodeReferenceKind) * head->referencesSize); + if(refs) + head->references = refs; + } else { + /* The array is empty. Remove. */ + UA_free(head->references); + head->references = NULL; } - - /* The array is empty. Remove. */ - UA_free(node->references); - node->references = NULL; } void UA_Node_deleteReferences(UA_Node *node) { - UA_Node_deleteReferencesSubset(node, 0, NULL); + UA_ReferenceTypeSet noRefs; + UA_ReferenceTypeSet_init(&noRefs); + UA_Node_deleteReferencesSubset(node, &noRefs); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -22820,12 +21554,15 @@ void UA_Node_deleteReferences(UA_Node *node) { * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB * Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang) * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes) + * Copyright 2022 (c) Fraunhofer IOSB (Author: Andreas Ebner) */ #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL #endif + #ifdef UA_ENABLE_SUBSCRIPTIONS #endif @@ -22845,7 +21582,7 @@ void UA_Node_deleteReferences(UA_Node *node) { * Application URI. * * This is done as soon as the Namespace Array is read or written via node value - * read / write services, or UA_Server_addNamespace, + * read / write services, or UA_Server_addNamespace, or UA_Server_getNamespaceByIndex * UA_Server_getNamespaceByName or UA_Server_run_startup is called. * * Therefore one has to set the custom NS1 URI before one of the previously @@ -22871,14 +21608,13 @@ UA_UInt16 addNamespace(UA_Server *server, const UA_String name) { /* Make the array bigger */ UA_String *newNS = (UA_String*)UA_realloc(server->namespaces, sizeof(UA_String) * (server->namespacesSize + 1)); - if(!newNS) - return 0; + UA_CHECK_MEM(newNS, return 0); + server->namespaces = newNS; /* Copy the namespace string */ UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]); - if(retval != UA_STATUSCODE_GOOD) - return 0; + UA_CHECK_STATUS(retval, return 0); /* Announce the change (otherwise, the array appears unchanged) */ ++server->namespacesSize; @@ -22890,17 +21626,16 @@ UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) { UA_String nameString; nameString.length = strlen(name); nameString.data = (UA_Byte*)(uintptr_t)name; - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_UInt16 retVal = addNamespace(server, nameString); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retVal; } UA_ServerConfig* UA_Server_getConfig(UA_Server *server) { - if(!server) - return NULL; - return &server->config; + UA_CHECK_MEM(server, return NULL); + return &server->config; } UA_StatusCode @@ -22920,88 +21655,97 @@ getNamespaceByName(UA_Server *server, const UA_String namespaceUri, } UA_StatusCode +getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex, + UA_String *foundUri) { + /* ensure that the uri for ns1 is set up from the app description */ + setupNs1Uri(server); + UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND; + if(namespaceIndex > server->namespacesSize) + return res; + res = UA_String_copy(&server->namespaces[namespaceIndex], foundUri); + return res; +} + +UA_StatusCode UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri, size_t *foundIndex) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode res = getNamespaceByName(server, namespaceUri, foundIndex); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex, + UA_String *foundUri) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode res = getNamespaceByIndex(server, namespaceIndex, foundUri); + UA_UNLOCK(&server->serviceMutex); return res; } UA_StatusCode UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, UA_NodeIteratorCallback callback, void *handle) { - UA_LOCK(server->serviceMutex); - const UA_Node *parent = UA_NODESTORE_GET(server, &parentNodeId); - if(!parent) { - UA_UNLOCK(server->serviceMutex); - return UA_STATUSCODE_BADNODEIDINVALID; - } + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = parentNodeId; + bd.browseDirection = UA_BROWSEDIRECTION_BOTH; + bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_ISFORWARD; - /* TODO: We need to do an ugly copy of the references array since users may - * delete references from within the callback. In single-threaded mode this - * changes the same node we point at here. In multi-threaded mode, this - * creates a new copy as nodes are truly immutable. - * The callback could remove a node via the regular public API. - * This can remove a member of the nodes-array we iterate over... - * */ - UA_Node *parentCopy = UA_Node_copy_alloc(parent); - if(!parentCopy) { - UA_NODESTORE_RELEASE(server, parent); - UA_UNLOCK(server->serviceMutex); - return UA_STATUSCODE_BADUNEXPECTEDERROR; - } + UA_BrowseResult br = UA_Server_browse(server, 0, &bd); + UA_StatusCode res = br.statusCode; + UA_CHECK_STATUS(res, goto cleanup); - UA_StatusCode retval = UA_STATUSCODE_GOOD; - for(size_t i = parentCopy->referencesSize; i > 0; --i) { - UA_NodeReferenceKind *ref = &parentCopy->references[i - 1]; - for(size_t j = 0; j<ref->refTargetsSize; j++) { - UA_UNLOCK(server->serviceMutex); - retval = callback(ref->refTargets[j].targetId.nodeId, ref->isInverse, - ref->referenceTypeId, handle); - UA_LOCK(server->serviceMutex); - if(retval != UA_STATUSCODE_GOOD) - goto cleanup; - } + for(size_t i = 0; i < br.referencesSize; i++) { + if(!UA_ExpandedNodeId_isLocal(&br.references[i].nodeId)) + continue; + res = callback(br.references[i].nodeId.nodeId, !br.references[i].isForward, + br.references[i].referenceTypeId, handle); + UA_CHECK_STATUS(res, goto cleanup); } - cleanup: - UA_Node_clear(parentCopy); - UA_free(parentCopy); - - UA_NODESTORE_RELEASE(server, parent); - UA_UNLOCK(server->serviceMutex); - return retval; + UA_BrowseResult_clear(&br); + return res; } /********************/ /* Server Lifecycle */ /********************/ +static void +serverExecuteRepeatedCallback(UA_Server *server, UA_ApplicationCallback cb, + void *callbackApplication, void *data); + /* The server needs to be stopped before it can be deleted */ void UA_Server_delete(UA_Server *server) { - /* Delete all internal data */ + UA_LOCK(&server->serviceMutex); + UA_Server_deleteSecureChannels(server); - UA_LOCK(server->serviceMutex); session_list_entry *current, *temp; LIST_FOREACH_SAFE(current, &server->sessions, pointers, temp) { UA_Server_removeSession(server, current, UA_DIAGNOSTICEVENT_CLOSE); } - UA_UNLOCK(server->serviceMutex); UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]); #ifdef UA_ENABLE_SUBSCRIPTIONS UA_MonitoredItem *mon, *mon_tmp; LIST_FOREACH_SAFE(mon, &server->localMonitoredItems, listEntry, mon_tmp) { LIST_REMOVE(mon, listEntry); - UA_LOCK(server->serviceMutex); UA_MonitoredItem_delete(server, mon); - UA_UNLOCK(server->serviceMutex); } + /* Remove subscriptions without a session */ + UA_Subscription *sub, *sub_tmp; + LIST_FOREACH_SAFE(sub, &server->subscriptions, serverListEntry, sub_tmp) { + UA_Subscription_delete(server, sub); + } + UA_assert(server->monitoredItemsSize == 0); + UA_assert(server->subscriptionsSize == 0); + #ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS UA_ConditionList_delete(server); -#endif//UA_ENABLE_ALARMS_CONDITIONS +#endif #endif @@ -23010,7 +21754,7 @@ void UA_Server_delete(UA_Server *server) { #endif #ifdef UA_ENABLE_DISCOVERY - UA_DiscoveryManager_deleteMembers(&server->discoveryManager, server); + UA_DiscoveryManager_clear(&server->discoveryManager, server); #endif #if UA_MULTITHREADING >= 100 @@ -23018,22 +21762,21 @@ void UA_Server_delete(UA_Server *server) { #endif /* Clean up the Admin Session */ - UA_LOCK(server->serviceMutex); - UA_Session_deleteMembersCleanup(&server->adminSession, server); - UA_UNLOCK(server->serviceMutex); + UA_Session_clear(&server->adminSession, server); - /* Clean up the work queue */ - UA_WorkQueue_cleanup(&server->workQueue); + UA_UNLOCK(&server->serviceMutex); /* The timer has its own mutex */ - /* Delete the timed work */ - UA_Timer_deleteMembers(&server->timer); + /* Execute all remaining delayed events and clean up the timer */ + UA_Timer_process(&server->timer, UA_DateTime_nowMonotonic() + 1, + (UA_TimerExecutionCallback)serverExecuteRepeatedCallback, server); + UA_Timer_clear(&server->timer); /* Clean up the config */ UA_ServerConfig_clean(&server->config); #if UA_MULTITHREADING >= 100 - UA_LOCK_DESTROY(server->networkMutex) - UA_LOCK_DESTROY(server->serviceMutex) + UA_LOCK_DESTROY(&server->networkMutex); + UA_LOCK_DESTROY(&server->serviceMutex); #endif /* Delete the server itself */ @@ -23043,29 +21786,34 @@ void UA_Server_delete(UA_Server *server) { /* Recurring cleanup. Removing unused and timed-out channels and sessions */ static void UA_Server_cleanup(UA_Server *server, void *_) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic(); UA_Server_cleanupSessions(server, nowMonotonic); UA_Server_cleanupTimedOutSecureChannels(server, nowMonotonic); #ifdef UA_ENABLE_DISCOVERY UA_Discovery_cleanupTimedOut(server, nowMonotonic); #endif - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } /********************/ /* Server Lifecycle */ /********************/ +static +UA_INLINE +UA_Boolean UA_Server_NodestoreIsConfigured(UA_Server *server) { + return server->config.nodestore.getNode != NULL; +} + static UA_Server * UA_Server_init(UA_Server *server) { + UA_StatusCode res = UA_STATUSCODE_GOOD; - - if(!server->config.nodestore.getNode) { - UA_LOG_FATAL(&server->config.logger, UA_LOGCATEGORY_SERVER, - "No Nodestore configured in the server"); - goto cleanup; - } + UA_CHECK_FATAL(UA_Server_NodestoreIsConfigured(server), goto cleanup, + &server->config.logger, UA_LOGCATEGORY_SERVER, + "No Nodestore configured in the server" + ); /* Init start time to zero, the actual start time will be sampled in * UA_Server_run_startup() */ @@ -23077,28 +21825,25 @@ UA_Server_init(UA_Server *server) { #endif #if UA_MULTITHREADING >= 100 - UA_LOCK_INIT(server->networkMutex) - UA_LOCK_INIT(server->serviceMutex) + UA_LOCK_INIT(&server->networkMutex); + UA_LOCK_INIT(&server->serviceMutex); #endif /* Initialize the handling of repeated callbacks */ UA_Timer_init(&server->timer); - UA_WorkQueue_init(&server->workQueue); - /* Initialize the adminSession */ UA_Session_init(&server->adminSession); server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID; server->adminSession.sessionId.identifier.guid.data1 = 1; server->adminSession.validTill = UA_INT64_MAX; + server->adminSession.sessionName = UA_STRING_ALLOC("Administrator"); /* Create Namespaces 0 and 1 * Ns1 will be filled later with the uri from the app description */ server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]); - if(!server->namespaces) { - UA_Server_delete(server); - return NULL; - } + UA_CHECK_MEM(server->namespaces, goto cleanup); + server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/"); server->namespaces[1] = UA_STRING_NULL; server->namespacesSize = 2; @@ -23123,14 +21868,20 @@ UA_Server_init(UA_Server *server) { /* Initialize namespace 0*/ res = UA_Server_initNS0(server); - if(res != UA_STATUSCODE_GOOD) - goto cleanup; + UA_CHECK_STATUS(res, goto cleanup); +#ifdef UA_ENABLE_PUBSUB /* Build PubSub information model */ #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL UA_Server_initPubSubNS0(server); #endif +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* setup default PubSub monitoring callbacks */ + res = UA_PubSubManager_setDefaultMonitoringCallbacks(&server->config.pubSubConfig.monitoringInterface); + UA_CHECK_STATUS(res, goto cleanup); +#endif /* UA_ENABLE_PUBSUB_MONITORING */ +#endif /* UA_ENABLE_PUBSUB */ return server; cleanup: @@ -23139,13 +21890,20 @@ UA_Server_init(UA_Server *server) { } UA_Server * -UA_Server_newWithConfig(const UA_ServerConfig *config) { - if(!config) - return NULL; +UA_Server_newWithConfig(UA_ServerConfig *config) { + UA_CHECK_MEM(config, return NULL); + UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server)); - if(!server) - return NULL; + UA_CHECK_MEM(server, UA_ServerConfig_clean(config); return NULL); + server->config = *config; + /* The config might have been "moved" into the server struct. Ensure that + * the logger pointer is correct. */ + for(size_t i = 0; i < server->config.securityPoliciesSize; i++) + server->config.securityPolicies[i].logger = &server->config.logger; + + /* Reset the old config */ + memset(config, 0, sizeof(UA_ServerConfig)); return UA_Server_init(server); } @@ -23169,11 +21927,12 @@ setServerShutdown(UA_Server *server) { UA_StatusCode UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback, void *data, UA_DateTime date, UA_UInt64 *callbackId) { - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = UA_Timer_addTimedCallback(&server->timer, - (UA_ApplicationCallback)callback, - server, data, date, callbackId); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + UA_Timer_addTimedCallback(&server->timer, + (UA_ApplicationCallback)callback, + server, data, date, callbackId); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -23183,32 +21942,35 @@ addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, UA_UInt64 *callbackId) { return UA_Timer_addRepeatedCallback(&server->timer, (UA_ApplicationCallback)callback, - server, data, interval_ms, callbackId); + server, data, interval_ms, NULL, + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, callbackId); } UA_StatusCode UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, void *data, UA_Double interval_ms, UA_UInt64 *callbackId) { - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = addRepeatedCallback(server, callback, data, interval_ms, callbackId); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + addRepeatedCallback(server, callback, data, interval_ms, callbackId); + UA_UNLOCK(&server->serviceMutex); return retval; } UA_StatusCode changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, - UA_Double interval_ms) { - return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, - interval_ms); + UA_Double interval_ms) { + return UA_Timer_changeRepeatedCallback(&server->timer, callbackId, + interval_ms, NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME); } UA_StatusCode UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, UA_Double interval_ms) { - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = changeRepeatedCallbackInterval(server, callbackId, interval_ms); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + changeRepeatedCallbackInterval(server, callbackId, interval_ms); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -23219,9 +21981,9 @@ removeCallback(UA_Server *server, UA_UInt64 callbackId) { void UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); removeCallback(server, callbackId); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } UA_StatusCode @@ -23232,18 +21994,18 @@ UA_Server_updateCertificate(UA_Server *server, UA_Boolean closeSessions, UA_Boolean closeSecureChannels) { - if(!server || !oldCertificate || !newCertificate || !newPrivateKey) - return UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK(server && oldCertificate && newCertificate && newPrivateKey, + return UA_STATUSCODE_BADINTERNALERROR); if(closeSessions) { session_list_entry *current; LIST_FOREACH(current, &server->sessions, pointers) { if(UA_ByteString_equal(oldCertificate, ¤t->session.header.channel->securityPolicy->localCertificate)) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_Server_removeSessionByToken(server, ¤t->session.header.authenticationToken, UA_DIAGNOSTICEVENT_CLOSE); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } } @@ -23261,11 +22023,11 @@ UA_Server_updateCertificate(UA_Server *server, while(i < server->config.endpointsSize) { UA_EndpointDescription *ed = &server->config.endpoints[i]; if(UA_ByteString_equal(&ed->serverCertificate, oldCertificate)) { - UA_String_deleteMembers(&ed->serverCertificate); + UA_String_clear(&ed->serverCertificate); UA_String_copy(newCertificate, &ed->serverCertificate); - UA_SecurityPolicy *sp = UA_SecurityPolicy_getSecurityPolicyByUri(server, &server->config.endpoints[i].securityPolicyUri); - if(!sp) - return UA_STATUSCODE_BADINTERNALERROR; + UA_SecurityPolicy *sp = getSecurityPolicyByUri(server, + &server->config.endpoints[i].securityPolicyUri); + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); sp->updateCertificateAndPrivateKey(sp, *newCertificate, *newPrivateKey); } i++; @@ -23279,8 +22041,7 @@ UA_Server_updateCertificate(UA_Server *server, /***************************/ UA_SecurityPolicy * -UA_SecurityPolicy_getSecurityPolicyByUri(const UA_Server *server, - const UA_ByteString *securityPolicyUri) { +getSecurityPolicyByUri(const UA_Server *server, const UA_ByteString *securityPolicyUri) { for(size_t i = 0; i < server->config.securityPoliciesSize; i++) { UA_SecurityPolicy *securityPolicyCandidate = &server->config.securityPolicies[i]; if(UA_ByteString_equal(securityPolicyUri, &securityPolicyCandidate->policyUri)) @@ -23294,27 +22055,47 @@ UA_SecurityPolicy_getSecurityPolicyByUri(const UA_Server *server, * SecurityPolicies */ static UA_StatusCode verifyServerApplicationURI(const UA_Server *server) { + const UA_String securityPolicyNoneUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); for(size_t i = 0; i < server->config.securityPoliciesSize; i++) { UA_SecurityPolicy *sp = &server->config.securityPolicies[i]; + if(UA_String_equal(&sp->policyUri, &securityPolicyNoneUri) && (sp->localCertificate.length == 0)) + continue; UA_StatusCode retval = server->config.certificateVerification. verifyApplicationURI(server->config.certificateVerification.context, &sp->localCertificate, &server->config.applicationDescription.applicationUri); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, - "The configured ApplicationURI does not match the URI " - "specified in the certificate for the SecurityPolicy %.*s", - (int)sp->policyUri.length, sp->policyUri.data); - return retval; - } + + UA_CHECK_STATUS_ERROR(retval, return retval, &server->config.logger, UA_LOGCATEGORY_SERVER, + "The configured ApplicationURI \"%.*s\"does not match the " + "ApplicationURI specified in the certificate for the " + "SecurityPolicy %.*s", + (int)server->config.applicationDescription.applicationUri.length, + server->config.applicationDescription.applicationUri.data, + (int)sp->policyUri.length, sp->policyUri.data); } return UA_STATUSCODE_GOOD; } #endif -UA_ServerStatistics UA_Server_getStatistics(UA_Server *server) -{ - return server->serverStats; +UA_ServerStatistics +UA_Server_getStatistics(UA_Server *server) { + UA_ServerStatistics stat; + stat.ns = server->networkStatistics; + stat.scs = server->secureChannelStatistics; + + stat.ss.currentSessionCount = server->activeSessionCount; + stat.ss.cumulatedSessionCount = + server->serverDiagnosticsSummary.cumulatedSessionCount; + stat.ss.securityRejectedSessionCount = + server->serverDiagnosticsSummary.securityRejectedSessionCount; + stat.ss.rejectedSessionCount = + server->serverDiagnosticsSummary.rejectedSessionCount; + stat.ss.sessionTimeoutCount = + server->serverDiagnosticsSummary.sessionTimeoutCount; + stat.ss.sessionAbortCount = + server->serverDiagnosticsSummary.sessionAbortCount; + + return stat; } /********************/ @@ -23338,18 +22119,19 @@ UA_Server_run_startup(UA_Server *server) { * E.g. if fuzzing is enabled, and two clients are connected, subscriptions do not work properly, * since the tokens will be overridden to allow easier fuzzing. */ UA_LOG_FATAL(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Server was built with unsafe fuzzing mode. This should only be used for specific fuzzing builds."); + "Server was built with unsafe fuzzing mode. " + "This should only be used for specific fuzzing builds."); #endif /* ensure that the uri for ns1 is set up from the app description */ setupNs1Uri(server); /* write ServerArray with same ApplicationURI value as NamespaceArray */ - UA_StatusCode retVal = writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY, - &server->config.applicationDescription.applicationUri, - 1, &UA_TYPES[UA_TYPES_STRING]); - if(retVal != UA_STATUSCODE_GOOD) - return retVal; + UA_StatusCode retVal = + writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY, + &server->config.applicationDescription.applicationUri, + 1, &UA_TYPES[UA_TYPES_STRING]); + UA_CHECK_STATUS(retVal, return retVal); if(server->state > UA_SERVERLIFECYCLE_FRESH) return UA_STATUSCODE_GOOD; @@ -23368,8 +22150,7 @@ UA_Server_run_startup(UA_Server *server) { /* Does the ApplicationURI match the local certificates? */ #ifdef UA_ENABLE_ENCRYPTION retVal = verifyServerApplicationURI(server); - if(retVal != UA_STATUSCODE_GOOD) - return retVal; + UA_CHECK_STATUS(retVal, return retVal); #endif /* Sample the start time and set it to the Server object */ @@ -23385,12 +22166,14 @@ UA_Server_run_startup(UA_Server *server) { UA_StatusCode result = UA_STATUSCODE_GOOD; for(size_t i = 0; i < server->config.networkLayersSize; ++i) { UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; - nl->statistics = &server->serverStats.ns; - result |= nl->start(nl, &server->config.customHostname); + nl->statistics = &server->networkStatistics; + result |= nl->start(nl, &server->config.logger, &server->config.customHostname); } + UA_CHECK_STATUS(result, return result); - /* Update the application description to match the previously added discovery urls. - * We can only do this after the network layer is started since it inits the discovery url */ + /* Update the application description to match the previously added + * discovery urls. We can only do this after the network layer is started + * since it inits the discovery url */ if(server->config.applicationDescription.discoveryUrlsSize != 0) { UA_Array_delete(server->config.applicationDescription.discoveryUrls, server->config.applicationDescription.discoveryUrlsSize, @@ -23399,27 +22182,30 @@ UA_Server_run_startup(UA_Server *server) { } server->config.applicationDescription.discoveryUrls = (UA_String *) UA_Array_new(server->config.networkLayersSize, &UA_TYPES[UA_TYPES_STRING]); - if(!server->config.applicationDescription.discoveryUrls) - return UA_STATUSCODE_BADOUTOFMEMORY; - server->config.applicationDescription.discoveryUrlsSize = server->config.networkLayersSize; + UA_CHECK_MEM(server->config.applicationDescription.discoveryUrls, + return UA_STATUSCODE_BADOUTOFMEMORY); + + server->config.applicationDescription.discoveryUrlsSize = + server->config.networkLayersSize; for(size_t i = 0; i < server->config.applicationDescription.discoveryUrlsSize; i++) { UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; - UA_String_copy(&nl->discoveryUrl, &server->config.applicationDescription.discoveryUrls[i]); + UA_String_copy(&nl->discoveryUrl, + &server->config.applicationDescription.discoveryUrls[i]); } - /* Spin up the worker threads */ -#if UA_MULTITHREADING >= 200 - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Spinning up %" PRIu16 " worker thread(s)", server->config.nThreads); - UA_WorkQueue_start(&server->workQueue, server->config.nThreads); -#endif - /* Start the multicast discovery server */ #ifdef UA_ENABLE_DISCOVERY_MULTICAST - if(server->config.discovery.mdnsEnable) + if(server->config.mdnsEnabled) startMulticastDiscoveryServer(server); #endif + /* Update Endpoint description */ + for(size_t i = 0; i < server->config.endpointsSize; ++i){ + UA_ApplicationDescription_clear(&server->config.endpoints[i].server); + UA_ApplicationDescription_copy(&server->config.applicationDescription, + &server->config.endpoints[i].server); + } + server->state = UA_SERVERLIFECYCLE_FRESH; return result; @@ -23427,12 +22213,12 @@ UA_Server_run_startup(UA_Server *server) { static void serverExecuteRepeatedCallback(UA_Server *server, UA_ApplicationCallback cb, - void *callbackApplication, void *data) { -#if UA_MULTITHREADING >= 200 - UA_WorkQueue_enqueue(&server->workQueue, cb, callbackApplication, data); -#else + void *callbackApplication, void *data) { + /* Service mutex is not set inside the timer that triggers the callback */ + /* The following check cannot be used since another thread can take the + * serviceMutex during a server_iterate_call. */ + //UA_LOCK_ASSERT(&server->serviceMutex, 0); cb(callbackApplication, data); -#endif } UA_UInt16 @@ -23468,12 +22254,15 @@ UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) { } } #endif + + UA_LOCK(&server->serviceMutex); + #if defined(UA_ENABLE_DISCOVERY_MULTICAST) && (UA_MULTITHREADING < 200) - if(server->config.discovery.mdnsEnable) { - // TODO multicastNextRepeat does not consider new input data (requests) - // on the socket. It will be handled on the next call. if needed, we - // need to use select with timeout on the multicast socket - // server->mdnsSocket (see example in mdnsd library) on higher level. + if(server->config.mdnsEnabled) { + /* TODO multicastNextRepeat does not consider new input data (requests) + * on the socket. It will be handled on the next call. if needed, we + * need to use select with timeout on the multicast socket + * server->mdnsSocket (see example in mdnsd library) on higher level. */ UA_DateTime multicastNextRepeat = 0; UA_StatusCode hasNext = iterateMulticastDiscoveryServer(server, &multicastNextRepeat, true); @@ -23482,9 +22271,7 @@ UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) { } #endif -#if UA_MULTITHREADING < 200 - UA_WorkQueue_manuallyProcessDelayed(&server->workQueue); -#endif + UA_UNLOCK(&server->serviceMutex); now = UA_DateTime_nowMonotonic(); timeout = 0; @@ -23501,23 +22288,12 @@ UA_Server_run_shutdown(UA_Server *server) { nl->stop(nl, server); } -#if UA_MULTITHREADING >= 200 - /* Shut down the workers */ - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Shutting down %u worker thread(s)", - (int unsigned)server->workQueue.workersSize); - UA_WorkQueue_stop(&server->workQueue); -#endif - #ifdef UA_ENABLE_DISCOVERY_MULTICAST /* Stop multicast discovery */ - if(server->config.discovery.mdnsEnable) + if(server->config.mdnsEnabled) stopMulticastDiscoveryServer(server); #endif - /* Execute all delayed callbacks */ - UA_WorkQueue_cleanup(&server->workQueue); - return UA_STATUSCODE_GOOD; } @@ -23531,8 +22307,8 @@ testShutdownCondition(UA_Server *server) { UA_StatusCode UA_Server_run(UA_Server *server, const volatile UA_Boolean *running) { UA_StatusCode retval = UA_Server_run_startup(server); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_CHECK_STATUS(retval, return retval); + #ifdef UA_ENABLE_VALGRIND_INTERACTIVE size_t loopCount = 0; #endif @@ -23553,56 +22329,20 @@ UA_Server_run(UA_Server *server, const volatile UA_Boolean *running) { return UA_Server_run_shutdown(server); } -#ifdef UA_ENABLE_HISTORIZING -/* Allow insert of historical data */ -UA_Boolean -UA_Server_AccessControl_allowHistoryUpdateUpdateData(UA_Server *server, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, - UA_PerformUpdateType performInsertReplace, - const UA_DataValue *value) { - if(server->config.accessControl.allowHistoryUpdateUpdateData && - !server->config.accessControl.allowHistoryUpdateUpdateData(server, &server->config.accessControl, - sessionId, sessionContext, nodeId, - performInsertReplace, value)) { - return false; - } - return true; -} - -/* Allow delete of historical data */ -UA_Boolean -UA_Server_AccessControl_allowHistoryUpdateDeleteRawModified(UA_Server *server, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, - UA_DateTime startTimestamp, - UA_DateTime endTimestamp, - bool isDeleteModified) { - if(server->config.accessControl.allowHistoryUpdateDeleteRawModified && - !server->config.accessControl.allowHistoryUpdateDeleteRawModified(server, &server->config.accessControl, - sessionId, sessionContext, nodeId, - startTimestamp, endTimestamp, - isDeleteModified)) { - return false; - } - return true; - -} -#endif /* UA_ENABLE_HISTORIZING */ - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_ns0.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_ns0.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2017 (c) Stefan Profanter, fortiss GmbH * Copyright 2017 (c) Thomas Bender * Copyright 2017 (c) Julian Grothoff * Copyright 2017 (c) Henrik Norrman * Copyright 2018 (c) Fabian Arndt, Root-Core * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) */ @@ -23616,9 +22356,8 @@ addNode_raw(UA_Server *server, UA_NodeClass nodeClass, item.nodeClass = nodeClass; item.requestedNewNodeId.nodeId = UA_NODEID_NUMERIC(0, nodeId); item.browseName = UA_QUALIFIEDNAME(0, name); - item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; - item.nodeAttributes.content.decoded.data = attributes; - item.nodeAttributes.content.decoded.type = attributesType; + UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, + attributes, attributesType); return AddNode_raw(server, &server->adminSession, NULL, &item, NULL); } @@ -23629,7 +22368,7 @@ addNode_finish(UA_Server *server, UA_UInt32 nodeId, const UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId); const UA_ExpandedNodeId targetId = UA_EXPANDEDNODEID_NUMERIC(0, parentNodeId); UA_StatusCode retval = UA_Server_addReference(server, sourceId, refTypeId, targetId, false); - if (retval != UA_STATUSCODE_GOOD) + if(retval != UA_STATUSCODE_GOOD) return retval; return AddNode_finish(server, &server->adminSession, &sourceId); } @@ -23670,7 +22409,10 @@ addReferenceTypeNode(UA_Server *server, char* name, char *inverseName, UA_UInt32 * compiler. */ static UA_StatusCode UA_Server_createNS0_base(UA_Server *server) { - /* Bootstrap References and HasSubtype */ + /* Bootstrap ReferenceTypes. The order of these is important for the + * ReferenceTypeIndex. The ReferenceTypeIndex is created with the raw node. + * The ReferenceTypeSet of subtypes for every ReferenceType is created + * during the call to AddNode_finish. */ UA_StatusCode ret = UA_STATUSCODE_GOOD; UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default; references_attr.displayName = UA_LOCALIZEDTEXT("", "References"); @@ -23744,6 +22486,9 @@ UA_Server_createNS0_base(UA_Server *server) { ret |= addReferenceTypeNode(server, "HasOrderedComponent", "OrderedComponentOf", UA_NS0ID_HASORDEREDCOMPONENT, false, false, UA_NS0ID_HASCOMPONENT); + ret |= addReferenceTypeNode(server, "HasInterface", "InterfaceOf", + UA_NS0ID_HASINTERFACE, false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + /**************/ /* Data Types */ /**************/ @@ -23912,7 +22657,8 @@ readStatus(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, statustype->secondsTillShutdown = 0; if(server->endTime != 0) { statustype->state = UA_SERVERSTATE_SHUTDOWN; - statustype->secondsTillShutdown = (UA_UInt32)((server->endTime - UA_DateTime_now()) / UA_DATETIME_SEC); + statustype->secondsTillShutdown = (UA_UInt32) + ((server->endTime - UA_DateTime_now()) / UA_DATETIME_SEC); } value->value.data = statustype; @@ -24124,9 +22870,13 @@ readMinSamplingInterval(UA_Server *server, const UA_NodeId *sessionId, void *ses } UA_StatusCode retval; - retval = UA_Variant_setScalarCopy(&value->value, - &server->config.samplingIntervalLimits.min, - &UA_TYPES[UA_TYPES_DURATION]); + UA_Duration minInterval; +#ifdef UA_ENABLE_SUBSCRIPTIONS + minInterval = server->config.samplingIntervalLimits.min; +#else + minInterval = 0.0; +#endif + retval = UA_Variant_setScalarCopy(&value->value, &minInterval, &UA_TYPES[UA_TYPES_DURATION]); if(retval != UA_STATUSCODE_GOOD) return retval; value->hasValue = true; @@ -24142,53 +22892,77 @@ readMinSamplingInterval(UA_Server *server, const UA_NodeId *sessionId, void *ses static UA_StatusCode readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, - void *objectContext, size_t inputSize, - const UA_Variant *input, size_t outputSize, - UA_Variant *output) { - UA_LOCK(server->serviceMutex); + void *objectContext, size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + /* Return two empty arrays by default */ + UA_Variant_setArray(&output[0], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), + 0, &UA_TYPES[UA_TYPES_UINT32]); + UA_Variant_setArray(&output[1], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), + 0, &UA_TYPES[UA_TYPES_UINT32]); + + /* Get the Session */ + UA_LOCK(&server->serviceMutex); UA_Session *session = UA_Server_getSessionById(server, sessionId); - UA_UNLOCK(server->serviceMutex); - if(!session) + if(!session) { + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINTERNALERROR; - if (inputSize == 0 || !input[0].data) + } + if(inputSize == 0 || !input[0].data) { + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; - UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data)); - UA_LOCK(server->serviceMutex); - UA_Subscription* subscription = UA_Session_getSubscriptionById(session, subscriptionId); - UA_UNLOCK(server->serviceMutex); - if(!subscription) - { - if(LIST_EMPTY(&session->serverSubscriptions)) - { - UA_Variant_setArray(&output[0], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), - 0, &UA_TYPES[UA_TYPES_UINT32]); - UA_Variant_setArray(&output[1], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), - 0, &UA_TYPES[UA_TYPES_UINT32]); - - return UA_STATUSCODE_BADNOMATCH; - } + } + /* Get the Subscription */ + UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data)); + UA_Subscription *subscription = UA_Server_getSubscriptionById(server, subscriptionId); + if(!subscription) { + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; } + /* The Subscription is not attached to this Session */ + if(subscription->session != session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADUSERACCESSDENIED; + } + + /* Count the MonitoredItems */ UA_UInt32 sizeOfOutput = 0; UA_MonitoredItem* monitoredItem; LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { ++sizeOfOutput; } - if(sizeOfOutput==0) + if(sizeOfOutput == 0) { + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_GOOD; + } - UA_UInt32* clientHandles = (UA_UInt32 *)UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); - UA_UInt32* serverHandles = (UA_UInt32 *)UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + /* Allocate the output arrays */ + UA_UInt32 *clientHandles = (UA_UInt32*) + UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + if(!clientHandles) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + UA_UInt32 *serverHandles = (UA_UInt32*) + UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + if(!serverHandles) { + UA_UNLOCK(&server->serviceMutex); + UA_free(clientHandles); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Fill the array */ UA_UInt32 i = 0; LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { - clientHandles[i] = monitoredItem->clientHandle; + clientHandles[i] = monitoredItem->parameters.clientHandle; serverHandles[i] = monitoredItem->monitoredItemId; ++i; } UA_Variant_setArray(&output[0], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); UA_Variant_setArray(&output[1], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_GOOD; } #endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */ @@ -24231,6 +23005,7 @@ UA_Server_minimalServerObject(UA_Server *server) { retval |= addVariableNode(server, "ServerArray", UA_NS0ID_SERVER_SERVERARRAY, UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE); + retval |= addVariableNode(server, "NamespaceArray", UA_NS0ID_SERVER_NAMESPACEARRAY, UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE); @@ -24347,27 +23122,25 @@ addModellingRules(UA_Server *server) { * example server time. */ UA_StatusCode UA_Server_initNS0(UA_Server *server) { - /* Initialize base nodes which are always required an cannot be created * through the NS compiler */ server->bootstrapNS0 = true; UA_StatusCode retVal = UA_Server_createNS0_base(server); - server->bootstrapNS0 = false; - if(retVal != UA_STATUSCODE_GOOD) - return retVal; #ifdef UA_GENERATED_NAMESPACE_ZERO /* Load nodes and references generated from the XML ns0 definition */ - retVal = namespace0_generated(server); + retVal |= namespace0_generated(server); #else /* Create a minimal server object */ - retVal = UA_Server_minimalServerObject(server); + retVal |= UA_Server_minimalServerObject(server); #endif + server->bootstrapNS0 = false; + if(retVal != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Initialization of Namespace 0 (before bootstrapping) " - "failed with %s. See previous outputs for any error messages.", + "Initialization of Namespace 0 failed with %s. " + "See previous outputs for any error messages.", UA_StatusCode_name(retVal)); return UA_STATUSCODE_BADINTERNALERROR; } @@ -24394,8 +23167,9 @@ UA_Server_initNS0(UA_Server *server) { /* CurrentTime */ UA_DataSource currentTime = {readCurrentTime, NULL}; - retVal |= UA_Server_setVariableNode_dataSource(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), currentTime); + UA_NodeId currTime = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + retVal |= UA_Server_setVariableNode_dataSource(server, currTime, currentTime); + retVal |= UA_Server_writeMinimumSamplingInterval(server, currTime, 100.0); /* State */ retVal |= UA_Server_setVariableNode_dataSource(server, @@ -24454,15 +23228,12 @@ UA_Server_initNS0(UA_Server *server) { retVal |= UA_Server_setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVICELEVEL), serviceLevel); - /* ServerDiagnostics - ServerDiagnosticsSummary */ - UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary; - UA_ServerDiagnosticsSummaryDataType_init(&serverDiagnosticsSummary); - retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY, - &serverDiagnosticsSummary, - &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE]); - /* ServerDiagnostics - EnabledFlag */ +#ifdef UA_ENABLE_DIAGNOSTICS + UA_Boolean enabledFlag = true; +#else UA_Boolean enabledFlag = false; +#endif retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG, &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]); @@ -24562,7 +23333,6 @@ UA_Server_initNS0(UA_Server *server) { retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL, &server->config.maxMonitoredItemsPerCall, &UA_TYPES[UA_TYPES_UINT32]); -#ifdef UA_ENABLE_MICRO_EMB_DEV_PROFILE /* Remove unused operation limit components */ UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADDATA), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADEVENTS), true); @@ -24573,26 +23343,100 @@ UA_Server_initNS0(UA_Server *server) { UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXARRAYLENGTH), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBYTESTRINGLENGTH), true); - /* Remove not supported Server Instance */ - UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DICTIONARIES), true); + /* Remove not supported server configurations */ UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_ESTIMATEDRETURNTIME), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_LOCALTIME), true); - UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), true); - UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACES), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_REQUESTSERVERSTATECHANGE), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_RESENDDATA), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SETSUBSCRIPTIONDURABLE), true); +#ifdef UA_ENABLE_DIAGNOSTICS + /* ServerDiagnostics - ServerDiagnosticsSummary */ + UA_DataSource serverDiagSummary = {readDiagnostics, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - ServerViewCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - CurrentSessionCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - CumulatedSessionCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - SecurityRejectedSessionCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - RejectedSessionCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - SessionTimeoutCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - SessionAbortCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - CurrentSubscriptionCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - CumulatedSubscriptionCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - PublishingIntervalCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - SecurityRejectedRequestsCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT), serverDiagSummary); + + /* ServerDiagnostics - ServerDiagnosticsSummary - RejectedRequestsCount */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT), serverDiagSummary); + + /* ServerDiagnostics - SubscriptionDiagnosticsArray */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_DataSource serverSubDiagSummary = {readSubscriptionDiagnosticsArray, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), serverSubDiagSummary); +#endif + + /* ServerDiagnostics - SessionDiagnosticsSummary - SessionDiagnosticsArray */ + UA_DataSource sessionDiagSummary = {readSessionDiagnosticsArray, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONDIAGNOSTICSARRAY), sessionDiagSummary); + + /* ServerDiagnostics - SessionDiagnosticsSummary - SessionSecurityDiagnosticsArray */ + UA_DataSource sessionSecDiagSummary = {readSessionSecurityDiagnostics, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONSECURITYDIAGNOSTICSARRAY), sessionSecDiagSummary); + +#else + /* Removing these NodeIds make Server Object to be non-complaint with UA + * 1.03 in CTT (Base Inforamtion/Base Info Core Structure/ 001.js) In the + * 1.04 specification this has been resolved by allowing to remove these + * static nodes as well */ UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SAMPLINGINTERVALDIAGNOSTICSARRAY), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY), true); - - /* Removing these NodeIds make Server Object to be non-complaint with UA 1.03 in CTT (Base Inforamtion/Base Info Core Structure/ 001.js) - * In the 1.04 specification this has been resolved by allowing to remove these static nodes as well */ UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), true); UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), true); #endif +#ifndef UA_ENABLE_PUBSUB + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), true); +#endif + #ifndef UA_ENABLE_HISTORIZING UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HISTORYSERVERCAPABILITIES), true); #else @@ -24654,7 +23498,7 @@ UA_Server_initNS0(UA_Server *server) { #endif #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) - retVal |= UA_Server_setMethodNode_callback(server, + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), readMonitoredItems); #endif @@ -24664,21 +23508,6 @@ UA_Server_initNS0(UA_Server *server) { #endif /* UA_GENERATED_NAMESPACE_ZERO */ - /* create the OverFlowEventType - * The EventQueueOverflowEventType is defined as abstract, therefore we can not create an instance of that type - * directly, but need to create a subtype. This is already posted on the OPC Foundation bug tracker under the - * following link for clarification: https://opcfoundation-onlineapplications.org/mantis/view.php?id=4206 */ -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - UA_ObjectTypeAttributes overflowAttr = UA_ObjectTypeAttributes_default; - overflowAttr.description = UA_LOCALIZEDTEXT("en-US", "A simple event for indicating a queue overflow."); - overflowAttr.displayName = UA_LOCALIZEDTEXT("en-US", "SimpleOverflowEventType"); - retVal |= UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SIMPLEOVERFLOWEVENTTYPE), - UA_NODEID_NUMERIC(0, UA_NS0ID_EVENTQUEUEOVERFLOWEVENTTYPE), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), - UA_QUALIFIEDNAME(0, "SimpleOverflowEventType"), - overflowAttr, NULL, NULL); -#endif - if(retVal != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Initialization of Namespace 0 (after bootstrapping) " @@ -24689,7 +23518,577 @@ UA_Server_initNS0(UA_Server *server) { return UA_STATUSCODE_GOOD; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_config.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_ns0_diagnostics.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + + +#ifdef UA_ENABLE_DIAGNOSTICS + +static UA_Boolean +equalBrowseName(UA_String *bn, char *n) { + UA_String name = UA_STRING(n); + return UA_String_equal(bn, &name); +} + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +/****************************/ +/* Subscription Diagnostics */ +/****************************/ + +static void +fillSubscriptionDiagnostics(UA_Subscription *sub, + UA_SubscriptionDiagnosticsDataType *diag) { + UA_NodeId_copy(&sub->session->sessionId, &diag->sessionId); /* ignore status */ + diag->subscriptionId = sub->subscriptionId; + diag->priority = sub->priority; + diag->publishingInterval = sub->publishingInterval; + diag->maxKeepAliveCount = sub->maxKeepAliveCount; + diag->maxLifetimeCount = sub->lifeTimeCount; + diag->maxNotificationsPerPublish = sub->notificationsPerPublish; + diag->publishingEnabled = sub->publishingEnabled; + diag->modifyCount = sub->modifyCount; + diag->enableCount = sub->enableCount; + diag->disableCount = sub->disableCount; + diag->republishRequestCount = sub->republishRequestCount; + diag->republishMessageRequestCount = + sub->republishRequestCount; /* Always equal to the previous republishRequestCount */ + diag->republishMessageCount = sub->republishMessageCount; + diag->transferRequestCount = sub->transferRequestCount; + diag->transferredToAltClientCount = sub->transferredToAltClientCount; + diag->transferredToSameClientCount = sub->transferredToSameClientCount; + diag->publishRequestCount = sub->publishRequestCount; + diag->dataChangeNotificationsCount = sub->dataChangeNotificationsCount; + diag->eventNotificationsCount = sub->eventNotificationsCount; + diag->notificationsCount = sub->notificationsCount; + diag->latePublishRequestCount = sub->latePublishRequestCount; + diag->currentKeepAliveCount = sub->currentKeepAliveCount; + diag->currentLifetimeCount = sub->currentLifetimeCount; + diag->unacknowledgedMessageCount = (UA_UInt32)sub->retransmissionQueueSize; + diag->discardedMessageCount = sub->discardedMessageCount; + diag->monitoredItemCount = sub->monitoredItemsSize; + diag->monitoringQueueOverflowCount = sub->monitoringQueueOverflowCount; + diag->nextSequenceNumber = sub->nextSequenceNumber; + diag->eventQueueOverFlowCount = sub->eventQueueOverFlowCount; + + /* Count the disabled MonitoredItems */ + UA_MonitoredItem *mon; + LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { + if(mon->monitoringMode == UA_MONITORINGMODE_DISABLED) + diag->disabledMonitoredItemCount++; + } +} + +/* The node context points to the subscription */ +static UA_StatusCode +readSubscriptionDiagnostics(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + /* Check the Subscription pointer */ + UA_Subscription *sub = (UA_Subscription*)nodeContext; + if(!sub) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Read the BrowseName */ + UA_QualifiedName bn; + UA_StatusCode res = readWithReadValue(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &bn); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Set the value */ + UA_SubscriptionDiagnosticsDataType sddt; + UA_SubscriptionDiagnosticsDataType_init(&sddt); + fillSubscriptionDiagnostics(sub, &sddt); + + char memberName[128]; + memcpy(memberName, bn.name.data, bn.name.length); + memberName[bn.name.length] = 0; + + size_t memberOffset; + const UA_DataType *memberType; + UA_Boolean isArray; + UA_Boolean found = + UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE], + memberName, &memberOffset, &memberType, &isArray); + if(!found) { + /* Not the member, but the main subscription diagnostics variable... */ + memberOffset = 0; + memberType = &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]; + } + + void *content = (void*)(((uintptr_t)&sddt) + memberOffset); + res = UA_Variant_setScalarCopy(&value->value, content, memberType); + if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) + value->hasValue = true; + + UA_SubscriptionDiagnosticsDataType_clear(&sddt); + UA_QualifiedName_clear(&bn); + return res; +} + +/* If the nodeContext == NULL, return all subscriptions in the server. + * Otherwise only for the current session. */ +UA_StatusCode +readSubscriptionDiagnosticsArray(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + /* Get the current session */ + size_t sdSize = 0; + UA_Session *session = NULL; + session_list_entry *sentry; + if(nodeContext) { + session = UA_Server_getSessionById(server, sessionId); + if(!session) + return UA_STATUSCODE_BADINTERNALERROR; + sdSize = session->subscriptionsSize; + } else { + LIST_FOREACH(sentry, &server->sessions, pointers) { + sdSize += sentry->session.subscriptionsSize; + } + } + + /* Allocate the output array */ + UA_SubscriptionDiagnosticsDataType *sd = (UA_SubscriptionDiagnosticsDataType*) + UA_Array_new(sdSize, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]); + if(!sd) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Collect the statistics */ + size_t i = 0; + UA_Subscription *sub; + if(session) { + TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) { + fillSubscriptionDiagnostics(sub, &sd[i]); + i++; + } + } else { + LIST_FOREACH(sentry, &server->sessions, pointers) { + TAILQ_FOREACH(sub, &sentry->session.subscriptions, sessionListEntry) { + fillSubscriptionDiagnostics(sub, &sd[i]); + i++; + } + } + } + + /* Set the output */ + value->hasValue = true; + UA_Variant_setArray(&value->value, sd, sdSize, + &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]); + return UA_STATUSCODE_GOOD; +} + +void +createSubscriptionObject(UA_Server *server, UA_Session *session, + UA_Subscription *sub) { + UA_ExpandedNodeId *children = NULL; + size_t childrenSize = 0; + UA_ReferenceTypeSet refTypes; + UA_NodeId hasComponent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); + + char subIdStr[32]; + snprintf(subIdStr, 32, "%u", sub->subscriptionId); + + /* Find the NodeId of the SubscriptionDiagnosticsArray */ + UA_BrowsePath bp; + UA_BrowsePath_init(&bp); + bp.startingNode = sub->session->sessionId; + UA_RelativePathElement rpe[1]; + memset(rpe, 0, sizeof(UA_RelativePathElement) * 1); + rpe[0].targetName = UA_QUALIFIEDNAME(0, "SubscriptionDiagnosticsArray"); + bp.relativePath.elements = rpe; + bp.relativePath.elementsSize = 1; + UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp); + if(bpr.targetsSize < 1) + return; + + /* Create an object for the subscription. Instantiates all the mandatory + * children. */ + UA_VariableAttributes var_attr = UA_VariableAttributes_default; + var_attr.displayName.text = UA_STRING(subIdStr); + var_attr.dataType = UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE].typeId; + UA_NodeId refId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); + UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, subIdStr); + UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SUBSCRIPTIONDIAGNOSTICSTYPE); + UA_NodeId objId = UA_NODEID_NUMERIC(1, 0); /* 0 => assign a random free id */ + UA_StatusCode res = addNode(server, UA_NODECLASS_VARIABLE, + &objId, + &bpr.targets[0].targetId.nodeId /* parent */, + &refId, browseName, &typeId, + (UA_NodeAttributes*)&var_attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL, &objId); + UA_CHECK_STATUS(res, goto cleanup); + + /* Add a second reference from the overall SubscriptionDiagnosticsArray variable */ + const UA_NodeId subDiagArray = + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY); + res = addRef(server, session, &subDiagArray, &refId, &objId, true); + + /* Get all children (including the variable itself) and set the contenxt + callback */ + res = referenceTypeIndices(server, &hasComponent, &refTypes, false); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + res = browseRecursive(server, 1, &objId, + UA_BROWSEDIRECTION_FORWARD, &refTypes, + UA_NODECLASS_VARIABLE, true, &childrenSize, &children); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Add the callback to all variables */ + UA_DataSource subDiagSource = {readSubscriptionDiagnostics, NULL}; + for(size_t i = 0; i < childrenSize; i++) { + setVariableNode_dataSource(server, children[i].nodeId, subDiagSource); + setNodeContext(server, children[i].nodeId, sub); + } + + UA_Array_delete(children, childrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + + cleanup: + UA_BrowsePathResult_clear(&bpr); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "Creating the subscription diagnostics object failed " + "with StatusCode %s", UA_StatusCode_name(res)); + } +} + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/***********************/ +/* Session Diagnostics */ +/***********************/ + +static void +setSessionDiagnostics(UA_Session *session, UA_SessionDiagnosticsDataType *sd) { + UA_SessionDiagnosticsDataType_copy(&session->diagnostics, sd); + UA_NodeId_copy(&session->sessionId, &sd->sessionId); + UA_String_copy(&session->sessionName, &sd->sessionName); + UA_ApplicationDescription_copy(&session->clientDescription, + &sd->clientDescription); + sd->maxResponseMessageSize = session->maxResponseMessageSize; +#ifdef UA_ENABLE_SUBSCRIPTIONS + sd->currentPublishRequestsInQueue = (UA_UInt32)session->responseQueueSize; +#endif + sd->actualSessionTimeout = session->timeout; + + /* Set LocaleIds */ + UA_StatusCode res = + UA_Array_copy(session->localeIds, session->localeIdsSize, + (void **)&sd->localeIds, &UA_TYPES[UA_TYPES_STRING]); + if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) + sd->localeIdsSize = session->localeIdsSize; + + /* Set Subscription diagnostics */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + sd->currentSubscriptionsCount = (UA_UInt32)session->subscriptionsSize; + + UA_Subscription *sub; + TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) { + sd->currentMonitoredItemsCount += (UA_UInt32)sub->monitoredItemsSize; + } +#endif +} + +UA_StatusCode +readSessionDiagnosticsArray(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + /* Allocate the output array */ + UA_SessionDiagnosticsDataType *sd = (UA_SessionDiagnosticsDataType*) + UA_Array_new(server->sessionCount, + &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]); + if(!sd) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Collect the statistics */ + size_t i = 0; + session_list_entry *session; + LIST_FOREACH(session, &server->sessions, pointers) { + setSessionDiagnostics(&session->session, &sd[i]); + i++; + } + + /* Set the output */ + value->hasValue = true; + UA_Variant_setArray(&value->value, sd, server->sessionCount, + &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]); + return UA_STATUSCODE_GOOD; +} + +static void +setSessionSecurityDiagnostics(UA_Session *session, + UA_SessionSecurityDiagnosticsDataType *sd) { + UA_SessionSecurityDiagnosticsDataType_copy(&session->securityDiagnostics, sd); + UA_NodeId_copy(&session->sessionId, &sd->sessionId); + UA_SecureChannel *channel = session->header.channel; + if(channel) { + UA_ByteString_copy(&channel->remoteCertificate, &sd->clientCertificate); + UA_String_copy(&channel->securityPolicy->policyUri, &sd->securityPolicyUri); + sd->securityMode = channel->securityMode; + sd->encoding = UA_STRING_ALLOC("UA Binary"); /* The only one atm */ + sd->transportProtocol = UA_STRING_ALLOC("opc.tcp"); /* The only one atm */ + } +} + +static UA_StatusCode +readSessionDiagnostics(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + /* Get the Session */ + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Read the BrowseName */ + UA_QualifiedName bn; + UA_StatusCode res = readWithReadValue(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &bn); + if(res != UA_STATUSCODE_GOOD) + return res; + + union { + UA_SessionDiagnosticsDataType sddt; + UA_SessionSecurityDiagnosticsDataType ssddt; + } data; + void *content; + UA_Boolean isArray = false; + const UA_DataType *type = NULL; + UA_Boolean securityDiagnostics = false; + + char memberName[128]; + size_t memberOffset; + UA_Boolean found; + + if(equalBrowseName(&bn.name, "SubscriptionDiagnosticsArray")) { + /* Reuse the datasource callback. Forward a non-null nodeContext to + * indicate that we want to see only the subscriptions for the current + * session. */ + res = readSubscriptionDiagnosticsArray(server, sessionId, sessionContext, + nodeId, (void*)0x01, + sourceTimestamp, range, value); + goto cleanup; + } else if(equalBrowseName(&bn.name, "SessionDiagnostics")) { + setSessionDiagnostics(session, &data.sddt); + content = &data.sddt; + type = &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]; + goto set_value; + } else if(equalBrowseName(&bn.name, "SessionSecurityDiagnostics")) { + setSessionSecurityDiagnostics(session, &data.ssddt); + securityDiagnostics = true; + content = &data.ssddt; + type = &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]; + goto set_value; + } + + /* Try to find the member in SessionDiagnosticsDataType and + * SessionSecurityDiagnosticsDataType */ + memcpy(memberName, bn.name.data, bn.name.length); + memberName[bn.name.length] = 0; + found = UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE], + memberName, &memberOffset, &type, &isArray); + if(found) { + setSessionDiagnostics(session, &data.sddt); + content = (void*)(((uintptr_t)&data.sddt) + memberOffset); + } else { + found = UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE], + memberName, &memberOffset, &type, &isArray); + if(!found) { + res = UA_STATUSCODE_BADNOTIMPLEMENTED; + goto cleanup; + } + setSessionSecurityDiagnostics(session, &data.ssddt); + securityDiagnostics = true; + content = (void*)(((uintptr_t)&data.ssddt) + memberOffset); + } + + set_value: + if(!isArray) { + res = UA_Variant_setScalarCopy(&value->value, content, type); + } else { + size_t len = *(size_t*)content; + content = (void*)(((uintptr_t)content) + sizeof(size_t)); + res = UA_Variant_setArrayCopy(&value->value, content, len, type); + } + if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) + value->hasValue = true; + + if(securityDiagnostics) + UA_SessionSecurityDiagnosticsDataType_clear(&data.ssddt); + else + UA_SessionDiagnosticsDataType_clear(&data.sddt); + + cleanup: + UA_QualifiedName_clear(&bn); + return res; +} + +UA_StatusCode +readSessionSecurityDiagnostics(UA_Server *server, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, + UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + /* Allocate the output array */ + UA_SessionSecurityDiagnosticsDataType *sd = (UA_SessionSecurityDiagnosticsDataType*) + UA_Array_new(server->sessionCount, + &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]); + if(!sd) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Collect the statistics */ + size_t i = 0; + session_list_entry *session; + LIST_FOREACH(session, &server->sessions, pointers) { + setSessionSecurityDiagnostics(&session->session, &sd[i]); + i++; + } + + /* Set the output */ + value->hasValue = true; + UA_Variant_setArray(&value->value, sd, server->sessionCount, + &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]); + return UA_STATUSCODE_GOOD; +} + +void +createSessionObject(UA_Server *server, UA_Session *session) { + UA_ExpandedNodeId *children = NULL; + size_t childrenSize = 0; + UA_ReferenceTypeSet refTypes; + UA_NodeId hasComponent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); + + /* Create an object for the session. Instantiates all the mandatory children. */ + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.displayName.text = session->sessionName; + UA_NodeId parentId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY); + UA_NodeId refId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT); + UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, ""); + browseName.name = session->sessionName; /* shallow copy */ + UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SESSIONDIAGNOSTICSOBJECTTYPE); + UA_StatusCode res = addNode(server, UA_NODECLASS_OBJECT, + &session->sessionId, &parentId, &refId, browseName, &typeId, + (UA_NodeAttributes*)&object_attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, NULL); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Recursively browse all children */ + res = referenceTypeIndices(server, &hasComponent, &refTypes, false); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + res = browseRecursive(server, 1, &session->sessionId, + UA_BROWSEDIRECTION_FORWARD, &refTypes, + UA_NODECLASS_VARIABLE, false, &childrenSize, &children); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Add the callback to all variables */ + UA_DataSource sessionDiagSource = {readSessionDiagnostics, NULL}; + for(size_t i = 0; i < childrenSize; i++) { + setVariableNode_dataSource(server, children[i].nodeId, sessionDiagSource); + } + + cleanup: + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "Creating the session diagnostics object failed " + "with StatusCode %s", UA_StatusCode_name(res)); + } + UA_Array_delete(children, childrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); +} + +/***************************/ +/* Server-Wide Diagnostics */ +/***************************/ + +UA_StatusCode +readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp, + const UA_NumericRange *range, UA_DataValue *value) { + if(range) { + value->hasStatus = true; + value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; + return UA_STATUSCODE_GOOD; + } + + if(sourceTimestamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + + UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC); + + void *data = NULL; + const UA_DataType *type = &UA_TYPES[UA_TYPES_UINT32]; /* Default */ + + switch(nodeId->identifier.numeric) { + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY: + server->serverDiagnosticsSummary.currentSessionCount = + server->activeSessionCount; + data = &server->serverDiagnosticsSummary; + type = &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE]; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT: + data = &server->serverDiagnosticsSummary.serverViewCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT: + data = &server->activeSessionCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT: + data = &server->serverDiagnosticsSummary.cumulatedSessionCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT: + data = &server->serverDiagnosticsSummary.securityRejectedSessionCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT: + data = &server->serverDiagnosticsSummary.rejectedSessionCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT: + data = &server->serverDiagnosticsSummary.sessionTimeoutCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT: + data = &server->serverDiagnosticsSummary.sessionAbortCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT: + data = &server->serverDiagnosticsSummary.currentSubscriptionCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT: + data = &server->serverDiagnosticsSummary.cumulatedSubscriptionCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT: + data = &server->serverDiagnosticsSummary.publishingIntervalCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT: + data = &server->serverDiagnosticsSummary.securityRejectedRequestsCount; + break; + case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT: + data = &server->serverDiagnosticsSummary.rejectedRequestsCount; + break; + default: + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_StatusCode res = UA_Variant_setScalarCopy(&value->value, data, type); + if(res == UA_STATUSCODE_GOOD) + value->hasValue = true; + return res; +} + +#endif /* UA_ENABLE_DIAGNOSTICS */ + +/**** amalgamated original file "/src/server/ua_server_config.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -24706,14 +24105,14 @@ UA_ServerConfig_clean(UA_ServerConfig *config) { return; /* Server Description */ - UA_BuildInfo_deleteMembers(&config->buildInfo); - UA_ApplicationDescription_deleteMembers(&config->applicationDescription); + UA_BuildInfo_clear(&config->buildInfo); + UA_ApplicationDescription_clear(&config->applicationDescription); #ifdef UA_ENABLE_DISCOVERY_MULTICAST - UA_MdnsDiscoveryConfiguration_clear(&config->discovery.mdns); - UA_String_clear(&config->discovery.mdnsInterfaceIP); + UA_MdnsDiscoveryConfiguration_clear(&config->mdnsConfig); + UA_String_clear(&config->mdnsInterfaceIP); # if !defined(UA_HAS_GETIFADDR) - if (config->discovery.ipAddressListSize) { - UA_free(config->discovery.ipAddressList); + if (config->mdnsIpAddressListSize) { + UA_free(config->mdnsIpAddressList); } # endif #endif @@ -24727,7 +24126,7 @@ UA_ServerConfig_clean(UA_ServerConfig *config) { UA_free(config->networkLayers); config->networkLayers = NULL; config->networkLayersSize = 0; - UA_String_deleteMembers(&config->customHostname); + UA_String_clear(&config->customHostname); config->customHostname = UA_STRING_NULL; for(size_t i = 0; i < config->securityPoliciesSize; ++i) { @@ -24739,7 +24138,7 @@ UA_ServerConfig_clean(UA_ServerConfig *config) { config->securityPoliciesSize = 0; for(size_t i = 0; i < config->endpointsSize; ++i) - UA_EndpointDescription_deleteMembers(&config->endpoints[i]); + UA_EndpointDescription_clear(&config->endpoints[i]); UA_free(config->endpoints); config->endpoints = NULL; @@ -24770,15 +24169,19 @@ UA_ServerConfig_clean(UA_ServerConfig *config) { config->logger.clear(config->logger.context); config->logger.log = NULL; config->logger.clear = NULL; -} -void -UA_ServerConfig_setCustomHostname(UA_ServerConfig *config, - const UA_String customHostname) { - if(!config) - return; - UA_String_deleteMembers(&config->customHostname); - UA_String_copy(&customHostname, &config->customHostname); +#ifdef UA_ENABLE_PUBSUB +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + if(config->pubSubConfig.securityPolicies != NULL) { + for(size_t i = 0; i < config->pubSubConfig.securityPoliciesSize; i++) { + config->pubSubConfig.securityPolicies[i].clear(&config->pubSubConfig.securityPolicies[i]); + } + UA_free(config->pubSubConfig.securityPolicies); + config->pubSubConfig.securityPolicies = NULL; + config->pubSubConfig.securityPoliciesSize = 0; + } +#endif +#endif /* UA_ENABLE_PUBSUB */ } #ifdef UA_ENABLE_PUBSUB @@ -24786,35 +24189,28 @@ UA_ServerConfig_setCustomHostname(UA_ServerConfig *config, * demand. */ UA_StatusCode UA_ServerConfig_addPubSubTransportLayer(UA_ServerConfig *config, - UA_PubSubTransportLayer *pubsubTransportLayer) { - - if(config->pubsubTransportLayersSize == 0) { - config->pubsubTransportLayers = (UA_PubSubTransportLayer *) - UA_malloc(sizeof(UA_PubSubTransportLayer)); - } else { - config->pubsubTransportLayers = (UA_PubSubTransportLayer*) - UA_realloc(config->pubsubTransportLayers, - sizeof(UA_PubSubTransportLayer) * (config->pubsubTransportLayersSize + 1)); - } - - if(config->pubsubTransportLayers == NULL) + UA_PubSubTransportLayer pubsubTransportLayer) { + UA_PubSubTransportLayer *tmpLayers = (UA_PubSubTransportLayer*) + UA_realloc(config->pubSubConfig.transportLayers, + sizeof(UA_PubSubTransportLayer) * + (config->pubSubConfig.transportLayersSize + 1)); + if(tmpLayers == NULL) return UA_STATUSCODE_BADOUTOFMEMORY; - memcpy(&config->pubsubTransportLayers[config->pubsubTransportLayersSize], - pubsubTransportLayer, sizeof(UA_PubSubTransportLayer)); - config->pubsubTransportLayersSize++; - + config->pubSubConfig.transportLayers = tmpLayers; + config->pubSubConfig.transportLayers[config->pubSubConfig.transportLayersSize] = pubsubTransportLayer; + config->pubSubConfig.transportLayersSize++; return UA_STATUSCODE_GOOD; } #endif /* UA_ENABLE_PUBSUB */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_binary.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_binary.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2014-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2014-2016 (c) Sten Grüner * Copyright 2014-2015, 2017 (c) Florian Palm * Copyright 2015-2016 (c) Chris Iatrou @@ -24845,10 +24241,10 @@ void UA_debug_dumpCompleteChunk(UA_Server *const server, UA_Connection *const co /********************/ UA_StatusCode -sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 requestHandle, - const UA_DataType *responseType, UA_StatusCode statusCode) { - UA_Response response; - UA_init(&response, responseType); +sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, + UA_UInt32 requestHandle, UA_StatusCode statusCode) { + UA_ServiceFault response; + UA_ServiceFault_init(&response); UA_ResponseHeader *responseHeader = &response.responseHeader; responseHeader->requestHandle = requestHandle; responseHeader->timestamp = UA_DateTime_now(); @@ -24860,29 +24256,40 @@ sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 reque /* Send error message. Message type is MSG and not ERR, since we are on a * SecureChannel! */ - return UA_SecureChannel_sendSymmetricMessage(channel, requestId, UA_MESSAGETYPE_MSG, - &response, responseType); + return UA_SecureChannel_sendSymmetricMessage(channel, requestId, + UA_MESSAGETYPE_MSG, &response, + &UA_TYPES[UA_TYPES_SERVICEFAULT]); } - /* This is not an ERR message, the connection is not closed afterwards */ +/* This is not an ERR message, the connection is not closed afterwards */ static UA_StatusCode decodeHeaderSendServiceFault(UA_SecureChannel *channel, const UA_ByteString *msg, size_t offset, const UA_DataType *responseType, UA_UInt32 requestId, UA_StatusCode error) { UA_RequestHeader requestHeader; - UA_StatusCode retval = UA_RequestHeader_decodeBinary(msg, &offset, &requestHeader); + UA_StatusCode retval = + UA_decodeBinaryInternal(msg, &offset, &requestHeader, + &UA_TYPES[UA_TYPES_REQUESTHEADER], NULL); if(retval != UA_STATUSCODE_GOOD) return retval; - retval = sendServiceFault(channel, requestId, requestHeader.requestHandle, - responseType, error); + retval = sendServiceFault(channel, requestId, requestHeader.requestHandle, error); UA_RequestHeader_clear(&requestHeader); return retval; } +/* The counterOffset is the offset of the UA_ServiceCounterDataType for the + * service in the UA_ SessionDiagnosticsDataType. */ +#ifdef UA_ENABLE_DIAGNOSTICS +#define UA_SERVICECOUNTER_OFFSET(X) \ + *counterOffset = offsetof(UA_SessionDiagnosticsDataType, X) +#else +#define UA_SERVICECOUNTER_OFFSET(X) +#endif + static void getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, const UA_DataType **responseType, UA_Service *service, - UA_Boolean *requiresSession) { + UA_Boolean *requiresSession, size_t *counterOffset) { switch(requestTypeId) { case UA_NS0ID_GETENDPOINTSREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_GetEndpoints; @@ -24919,18 +24326,18 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, break; #endif case UA_NS0ID_CREATESESSIONREQUEST_ENCODING_DEFAULTBINARY: - *service = (UA_Service)(uintptr_t)Service_CreateSession; + *service = (UA_Service)Service_CreateSession; *requestType = &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]; *responseType = &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]; *requiresSession = false; break; case UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTBINARY: - *service = (UA_Service)(uintptr_t)Service_ActivateSession; + *service = (UA_Service)Service_ActivateSession; *requestType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]; *responseType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]; break; case UA_NS0ID_CLOSESESSIONREQUEST_ENCODING_DEFAULTBINARY: - *service = (UA_Service)(uintptr_t)Service_CloseSession; + *service = (UA_Service)Service_CloseSession; *requestType = &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]; *responseType = &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]; break; @@ -24939,36 +24346,43 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, *service = (UA_Service)Service_Read; *requestType = &UA_TYPES[UA_TYPES_READREQUEST]; *responseType = &UA_TYPES[UA_TYPES_READRESPONSE]; + UA_SERVICECOUNTER_OFFSET(readCount); break; case UA_NS0ID_WRITEREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_Write; *requestType = &UA_TYPES[UA_TYPES_WRITEREQUEST]; *responseType = &UA_TYPES[UA_TYPES_WRITERESPONSE]; + UA_SERVICECOUNTER_OFFSET(writeCount); break; case UA_NS0ID_BROWSEREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_Browse; *requestType = &UA_TYPES[UA_TYPES_BROWSEREQUEST]; *responseType = &UA_TYPES[UA_TYPES_BROWSERESPONSE]; + UA_SERVICECOUNTER_OFFSET(browseCount); break; case UA_NS0ID_BROWSENEXTREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_BrowseNext; *requestType = &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST]; *responseType = &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]; + UA_SERVICECOUNTER_OFFSET(browseNextCount); break; case UA_NS0ID_REGISTERNODESREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_RegisterNodes; *requestType = &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST]; *responseType = &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]; + UA_SERVICECOUNTER_OFFSET(registerNodesCount); break; case UA_NS0ID_UNREGISTERNODESREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_UnregisterNodes; *requestType = &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST]; *responseType = &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]; + UA_SERVICECOUNTER_OFFSET(unregisterNodesCount); break; case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_TranslateBrowsePathsToNodeIds; *requestType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST]; *responseType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]; + UA_SERVICECOUNTER_OFFSET(translateBrowsePathsToNodeIdsCount); break; #ifdef UA_ENABLE_SUBSCRIPTIONS @@ -24976,50 +24390,72 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, *service = (UA_Service)Service_CreateSubscription; *requestType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST]; *responseType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]; + UA_SERVICECOUNTER_OFFSET(createSubscriptionCount); break; case UA_NS0ID_PUBLISHREQUEST_ENCODING_DEFAULTBINARY: *requestType = &UA_TYPES[UA_TYPES_PUBLISHREQUEST]; *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]; + UA_SERVICECOUNTER_OFFSET(publishCount); break; case UA_NS0ID_REPUBLISHREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_Republish; *requestType = &UA_TYPES[UA_TYPES_REPUBLISHREQUEST]; *responseType = &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE]; + UA_SERVICECOUNTER_OFFSET(republishCount); break; case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_ModifySubscription; *requestType = &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST]; *responseType = &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]; + UA_SERVICECOUNTER_OFFSET(modifySubscriptionCount); break; case UA_NS0ID_SETPUBLISHINGMODEREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_SetPublishingMode; *requestType = &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST]; *responseType = &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]; + UA_SERVICECOUNTER_OFFSET(setPublishingModeCount); break; case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_DeleteSubscriptions; *requestType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST]; *responseType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]; + UA_SERVICECOUNTER_OFFSET(deleteSubscriptionsCount); + break; + case UA_NS0ID_TRANSFERSUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_TransferSubscriptions; + *requestType = &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSRESPONSE]; + UA_SERVICECOUNTER_OFFSET(transferSubscriptionsCount); break; case UA_NS0ID_CREATEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_CreateMonitoredItems; *requestType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST]; *responseType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]; + UA_SERVICECOUNTER_OFFSET(createMonitoredItemsCount); break; case UA_NS0ID_DELETEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_DeleteMonitoredItems; *requestType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST]; *responseType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]; + UA_SERVICECOUNTER_OFFSET(deleteMonitoredItemsCount); break; case UA_NS0ID_MODIFYMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_ModifyMonitoredItems; *requestType = &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST]; *responseType = &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]; + UA_SERVICECOUNTER_OFFSET(modifyMonitoredItemsCount); break; case UA_NS0ID_SETMONITORINGMODEREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_SetMonitoringMode; *requestType = &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST]; *responseType = &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]; + UA_SERVICECOUNTER_OFFSET(setMonitoringModeCount); + break; + case UA_NS0ID_SETTRIGGERINGREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_SetTriggering; + *requestType = &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]; + UA_SERVICECOUNTER_OFFSET(setTriggeringCount); break; #endif #ifdef UA_ENABLE_HISTORIZING @@ -25028,12 +24464,14 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, *service = (UA_Service)Service_HistoryRead; *requestType = &UA_TYPES[UA_TYPES_HISTORYREADREQUEST]; *responseType = &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]; + UA_SERVICECOUNTER_OFFSET(historyReadCount); break; /* For History update */ case UA_NS0ID_HISTORYUPDATEREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_HistoryUpdate; *requestType = &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST]; *responseType = &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]; + UA_SERVICECOUNTER_OFFSET(historyUpdateCount); break; #endif @@ -25042,6 +24480,7 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, *service = (UA_Service)Service_Call; *requestType = &UA_TYPES[UA_TYPES_CALLREQUEST]; *responseType = &UA_TYPES[UA_TYPES_CALLRESPONSE]; + UA_SERVICECOUNTER_OFFSET(callCount); break; #endif @@ -25050,21 +24489,25 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, *service = (UA_Service)Service_AddNodes; *requestType = &UA_TYPES[UA_TYPES_ADDNODESREQUEST]; *responseType = &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]; + UA_SERVICECOUNTER_OFFSET(addNodesCount); break; case UA_NS0ID_ADDREFERENCESREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_AddReferences; *requestType = &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST]; *responseType = &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]; + UA_SERVICECOUNTER_OFFSET(addReferencesCount); break; case UA_NS0ID_DELETENODESREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_DeleteNodes; *requestType = &UA_TYPES[UA_TYPES_DELETENODESREQUEST]; *responseType = &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]; + UA_SERVICECOUNTER_OFFSET(deleteNodesCount); break; case UA_NS0ID_DELETEREFERENCESREQUEST_ENCODING_DEFAULTBINARY: *service = (UA_Service)Service_DeleteReferences; *requestType = &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST]; *responseType = &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]; + UA_SERVICECOUNTER_OFFSET(deleteReferencesCount); break; #endif @@ -25080,9 +24523,13 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, /* HEL -> Open up the connection */ static UA_StatusCode processHEL(UA_Server *server, UA_SecureChannel *channel, const UA_ByteString *msg) { - size_t offset = 8; /* Go to the beginning of the TcpHelloMessage */ + if(channel->state != UA_SECURECHANNELSTATE_FRESH) + return UA_STATUSCODE_BADINTERNALERROR; + size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */ UA_TcpHelloMessage helloMessage; - UA_StatusCode retval = UA_TcpHelloMessage_decodeBinary(msg, &offset, &helloMessage); + UA_StatusCode retval = + UA_decodeBinaryInternal(msg, &offset, &helloMessage, + &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], NULL); if(retval != UA_STATUSCODE_GOOD) return retval; @@ -25123,26 +24570,36 @@ processHEL(UA_Server *server, UA_SecureChannel *channel, const UA_ByteString *ms /* Encode and send the response */ UA_Byte *bufPos = ack_msg.data; const UA_Byte *bufEnd = &ack_msg.data[ack_msg.length]; - retval |= UA_TcpMessageHeader_encodeBinary(&ackHeader, &bufPos, bufEnd); - retval |= UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &bufPos, bufEnd); + retval |= UA_encodeBinaryInternal(&ackHeader, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &bufPos, &bufEnd, NULL, NULL); + retval |= UA_encodeBinaryInternal(&ackMessage, + &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], + &bufPos, &bufEnd, NULL, NULL); if(retval != UA_STATUSCODE_GOOD) { connection->releaseSendBuffer(connection, &ack_msg); return retval; } ack_msg.length = ackHeader.messageSize; - return connection->send(connection, &ack_msg); + retval = connection->send(connection, &ack_msg); + if(retval == UA_STATUSCODE_GOOD) + channel->state = UA_SECURECHANNELSTATE_ACK_SENT; + return retval; } /* OPN -> Open up/renew the securechannel */ static UA_StatusCode processOPN(UA_Server *server, UA_SecureChannel *channel, - const UA_UInt32 requestId, const UA_ByteString *msg, size_t offset) { + const UA_UInt32 requestId, const UA_ByteString *msg) { + if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT && + channel->state != UA_SECURECHANNELSTATE_OPEN) + return UA_STATUSCODE_BADINTERNALERROR; /* Decode the request */ UA_NodeId requestType; UA_OpenSecureChannelRequest openSecureChannelRequest; + size_t offset = 0; UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestType); - if(retval != UA_STATUSCODE_GOOD) { UA_NodeId_clear(&requestType); UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, @@ -25150,11 +24607,12 @@ processOPN(UA_Server *server, UA_SecureChannel *channel, UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_REJECT); return retval; } - retval = UA_OpenSecureChannelRequest_decodeBinary(msg, &offset, &openSecureChannelRequest); + retval = UA_decodeBinaryInternal(msg, &offset, &openSecureChannelRequest, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST], NULL); /* Error occurred */ if(retval != UA_STATUSCODE_GOOD || - requestType.identifier.numeric != UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId) { + !UA_NodeId_equal(&requestType, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId)) { UA_NodeId_clear(&requestType); UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest); UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, @@ -25190,84 +24648,18 @@ processOPN(UA_Server *server, UA_SecureChannel *channel, return retval; } -static UA_StatusCode -decryptProcessOPN(UA_Server *server, UA_SecureChannel *channel, - UA_ByteString *msg) { - UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, "Decrypt an OPN message"); - - /* Skip the first header. We know length and message type. */ - size_t offset = UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH; - - /* Decode the asymmetric algorithm security header and call the callback - * to perform checks. */ - UA_AsymmetricAlgorithmSecurityHeader asymHeader; - UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); - UA_StatusCode retval = - UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, &offset, &asymHeader); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, - "Could not decode the OPN header"); - return retval; - } - - /* Verify the certificate before creating the SecureChannel with it */ - if(asymHeader.senderCertificate.length > 0) { - retval = server->config.certificateVerification. - verifyCertificate(server->config.certificateVerification.context, - &asymHeader.senderCertificate); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, - "Could not verify the client's certificate"); - return retval; - } - } - - if(channel->state < UA_SECURECHANNELSTATE_OPEN) { - retval = UA_Server_configSecureChannel(server, channel, &asymHeader); - if(retval != UA_STATUSCODE_GOOD) { - UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); - return retval; - } - } - - retval = checkAsymHeader(channel, &asymHeader); - UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, - "Could not verify OPN header"); - return retval; - } - - retval = decryptAndVerifyChunk(channel, &channel->securityPolicy->asymmetricModule.cryptoModule, - UA_MESSAGETYPE_OPN, msg, offset); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, - "Could not decrypt and verify the OPN payload"); - return retval; - } - - /* Decode the sequence header */ - UA_SequenceHeader sequenceHeader; - retval = UA_SequenceHeader_decodeBinary(msg, &offset, &sequenceHeader); - if(retval != UA_STATUSCODE_GOOD) - return retval; - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - retval = processSequenceNumberAsym(channel, sequenceHeader.sequenceNumber); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, - "Could not process the OPN message's sequence number"); - return retval; - } -#endif - - return processOPN(server, channel, sequenceHeader.requestId, msg, offset); -} - /* The responseHeader must have the requestHandle already set */ UA_StatusCode sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, UA_UInt32 requestId, UA_Response *response, const UA_DataType *responseType) { + if(!channel) + return UA_STATUSCODE_BADINTERNALERROR; + + /* If the overall service call failed, answer with a ServiceFault */ + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) + return sendServiceFault(channel, requestId, response->responseHeader.requestHandle, + response->responseHeader.serviceResult); + /* Prepare the ResponseHeader */ response->responseHeader.timestamp = UA_DateTime_now(); @@ -25278,8 +24670,8 @@ sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, (unsigned)requestId, responseType->typeName); #else UA_LOG_DEBUG_SESSION(&server->config.logger, session, - "Sending reponse for RequestId %u of type %" PRIi16, - (unsigned)requestId, responseType->binaryEncodingId); + "Sending reponse for RequestId %u of type %" PRIu32, + (unsigned)requestId, responseType->binaryEncodingId.identifier.numeric); #endif } else { #ifdef UA_ENABLE_TYPEDESCRIPTION @@ -25288,8 +24680,8 @@ sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, (unsigned)requestId, responseType->typeName); #else UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, - "Sending reponse for RequestId %u of type %" PRIi16, - (unsigned)requestId, responseType->binaryEncodingId); + "Sending reponse for RequestId %u of type %" PRIu32, + (unsigned)requestId, responseType->binaryEncodingId.identifier.numeric); #endif } @@ -25300,12 +24692,12 @@ sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, return retval; /* Assert's required for clang-analyzer */ - UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH]); + UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]); UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]); /* Encode the response type */ - UA_NodeId typeId = UA_NODEID_NUMERIC(0, responseType->binaryEncodingId); - retval = UA_MessageContext_encode(&mc, &typeId, &UA_TYPES[UA_TYPES_NODEID]); + retval = UA_MessageContext_encode(&mc, &responseType->binaryEncodingId, + &UA_TYPES[UA_TYPES_NODEID]); if(retval != UA_STATUSCODE_GOOD) return retval; @@ -25334,15 +24726,24 @@ getBoundSession(UA_Server *server, const UA_SecureChannel *channel, continue; UA_Session *current = (UA_Session*)sh; /* Has the session timed out? */ - if(current->validTill < now) + if(current->validTill < now) { + server->serverDiagnosticsSummary.rejectedSessionCount++; return UA_STATUSCODE_BADSESSIONCLOSED; + } *session = current; return UA_STATUSCODE_GOOD; } + server->serverDiagnosticsSummary.rejectedSessionCount++; + /* Session exists on another SecureChannel. The CTT expect this error. */ - if(getSessionByToken(server, token)) + UA_Session *tmpSession = getSessionByToken(server, token); + if(tmpSession) { +#ifdef UA_ENABLE_DIAGNOSTICS + tmpSession->diagnostics.unauthorizedRequestCount++; +#endif return UA_STATUSCODE_BADSECURECHANNELIDINVALID; + } return UA_STATUSCODE_GOOD; } @@ -25350,11 +24751,17 @@ getBoundSession(UA_Server *server, const UA_SecureChannel *channel, static const UA_String securityPolicyNone = UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#None"); +/* Returns a status of the SecureChannel. The detailed service status (usually + * part of the response) is set in the serviceResult argument. */ static UA_StatusCode processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId, UA_Service service, const UA_Request *request, const UA_DataType *requestType, UA_Response *response, - const UA_DataType *responseType, UA_Boolean sessionRequired) { + const UA_DataType *responseType, UA_Boolean sessionRequired, + size_t counterOffset) { + UA_Session *session = NULL; + UA_StatusCode channelRes = UA_STATUSCODE_GOOD; + UA_StatusCode serviceRes = UA_STATUSCODE_GOOD; const UA_RequestHeader *requestHeader = &request->requestHeader; /* If it is an unencrypted (#None) channel, only allow the discovery services */ @@ -25366,17 +24773,19 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques && requestType != &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST] #endif ) { - return sendServiceFault(channel, requestId, requestHeader->requestHandle, - responseType, UA_STATUSCODE_BADSECURITYPOLICYREJECTED); + serviceRes = UA_STATUSCODE_BADSECURITYPOLICYREJECTED; + channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle, + UA_STATUSCODE_BADSECURITYPOLICYREJECTED); + goto update_statistics; } /* Session lifecycle services. */ if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST] || requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST] || requestType == &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]) { - UA_LOCK(server->serviceMutex); - ((UA_ChannelService)(uintptr_t)service)(server, channel, request, response); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + ((UA_ChannelService)service)(server, channel, request, response); + UA_UNLOCK(&server->serviceMutex); #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Store the authentication token so we can help fuzzing by setting * these values in the next request automatically */ @@ -25385,17 +24794,24 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques UA_NodeId_copy(&res->authenticationToken, &unsafe_fuzz_authenticationToken); } #endif - return sendResponse(server, NULL, channel, requestId, response, responseType); + serviceRes = response->responseHeader.serviceResult; + channelRes = sendResponse(server, NULL, channel, requestId, response, responseType); + goto update_statistics; } /* Get the Session bound to the SecureChannel (not necessarily activated) */ - UA_Session *session = NULL; - UA_StatusCode retval = UA_STATUSCODE_GOOD; if(!UA_NodeId_isNull(&requestHeader->authenticationToken)) { - retval = getBoundSession(server, channel, &requestHeader->authenticationToken, &session); - if(retval != UA_STATUSCODE_GOOD) - return sendServiceFault(channel, requestId, requestHeader->requestHandle, - responseType, retval); + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + getBoundSession(server, channel, + &requestHeader->authenticationToken, &session); + UA_UNLOCK(&server->serviceMutex); + if(retval != UA_STATUSCODE_GOOD) { + serviceRes = response->responseHeader.serviceResult; + channelRes = sendServiceFault(channel, requestId, + requestHeader->requestHandle, retval); + goto update_statistics; + } } /* Set an anonymous, inactive session for services that need no session */ @@ -25408,11 +24824,13 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques requestType->typeName); #else UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, - "Service %" PRIi16 " refused without a valid session", - requestType->binaryEncodingId); + "Service %" PRIu32 " refused without a valid session", + requestType->binaryEncodingId.identifier.numeric); #endif - return sendServiceFault(channel, requestId, requestHeader->requestHandle, - responseType, UA_STATUSCODE_BADSESSIONIDINVALID); + serviceRes = UA_STATUSCODE_BADSESSIONIDINVALID; + channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle, + UA_STATUSCODE_BADSESSIONIDINVALID); + goto update_statistics; } UA_Session_init(&anonymousSession); @@ -25431,17 +24849,19 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques requestType->typeName); #else UA_LOG_WARNING_SESSION(&server->config.logger, session, - "Service %" PRIi16 " refused on a non-activated session", - requestType->binaryEncodingId); + "Service %" PRIu32 " refused on a non-activated session", + requestType->binaryEncodingId.identifier.numeric); #endif if(session != &anonymousSession) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_Server_removeSessionByToken(server, &session->header.authenticationToken, UA_DIAGNOSTICEVENT_ABORT); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } - return sendServiceFault(channel, requestId, requestHeader->requestHandle, - responseType, UA_STATUSCODE_BADSESSIONNOTACTIVATED); + serviceRes = UA_STATUSCODE_BADSESSIONNOTACTIVATED; + channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle, + UA_STATUSCODE_BADSESSIONNOTACTIVATED); + goto update_statistics; } /* Update the session lifetime */ @@ -25450,10 +24870,11 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques #ifdef UA_ENABLE_SUBSCRIPTIONS /* The publish request is not answered immediately */ if(requestType == &UA_TYPES[UA_TYPES_PUBLISHREQUEST]) { - UA_LOCK(server->serviceMutex); - Service_Publish(server, session, &request->publishRequest, requestId); - UA_UNLOCK(server->serviceMutex); - return UA_STATUSCODE_GOOD; + UA_LOCK(&server->serviceMutex); + serviceRes = Service_Publish(server, session, &request->publishRequest, requestId); + /* No channelRes due to the async response */ + UA_UNLOCK(&server->serviceMutex); + goto update_statistics; } #endif @@ -25461,30 +24882,59 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques /* The call request might not be answered immediately */ if(requestType == &UA_TYPES[UA_TYPES_CALLREQUEST]) { UA_Boolean finished = true; - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Service_CallAsync(server, session, requestId, &request->callRequest, &response->callResponse, &finished); - UA_UNLOCK(server->serviceMutex); - - /* Async method calls remain. Don't send a response now */ - if(!finished) - return UA_STATUSCODE_GOOD; + UA_UNLOCK(&server->serviceMutex); - /* We are done here */ - return sendResponse(server, session, channel, requestId, response, responseType); + /* Async method calls remain. Don't send a response now. In case we have + * an async call, count as a "good" request for the diagnostics + * statistic. */ + if(UA_LIKELY(finished)) { + serviceRes = response->responseHeader.serviceResult; + channelRes = sendResponse(server, session, channel, + requestId, response, responseType); + } + goto update_statistics; } #endif - /* Dispatch the synchronous service call and send the response */ - UA_LOCK(server->serviceMutex); + /* Execute the synchronous service call */ + UA_LOCK(&server->serviceMutex); service(server, session, request, response); - UA_UNLOCK(server->serviceMutex); - return sendResponse(server, session, channel, requestId, response, responseType); + UA_UNLOCK(&server->serviceMutex); + + /* Send the response */ + serviceRes = response->responseHeader.serviceResult; + channelRes = sendResponse(server, session, channel, requestId, response, responseType); + + /* Update the diagnostics statistics */ + update_statistics: +#ifdef UA_ENABLE_DIAGNOSTICS + if(session && session != &server->adminSession) { + session->diagnostics.totalRequestCount.totalCount++; + if(serviceRes != UA_STATUSCODE_GOOD) + session->diagnostics.totalRequestCount.errorCount++; + if(counterOffset != 0) { + UA_ServiceCounterDataType *serviceCounter = (UA_ServiceCounterDataType*) + (((uintptr_t)&session->diagnostics) + counterOffset); + serviceCounter->totalCount++; + if(serviceRes != UA_STATUSCODE_GOOD) + serviceCounter->errorCount++; + } + } +#else + (void)serviceRes; /* Pacify compiler warnings */ +#endif + + return channelRes; } static UA_StatusCode processMSG(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId, const UA_ByteString *msg) { + if(channel->state != UA_SECURECHANNELSTATE_OPEN) + return UA_STATUSCODE_BADINTERNALERROR; /* Decode the nodeid */ size_t offset = 0; UA_NodeId requestTypeId; @@ -25502,12 +24952,14 @@ processMSG(UA_Server *server, UA_SecureChannel *channel, UA_Boolean sessionRequired = true; const UA_DataType *requestType = NULL; const UA_DataType *responseType = NULL; + size_t counterOffset = 0; getServicePointers(requestTypeId.identifier.numeric, &requestType, - &responseType, &service, &sessionRequired); + &responseType, &service, &sessionRequired, &counterOffset); if(!requestType) { - if(requestTypeId.identifier.numeric == 787) { + if(requestTypeId.identifier.numeric == + UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY) { UA_LOG_INFO_CHANNEL(&server->config.logger, channel, - "Client requested a subscription, " \ + "Client requested a subscription, " "but those are not enabled in the build"); } else { UA_LOG_INFO_CHANNEL(&server->config.logger, channel, @@ -25522,7 +24974,8 @@ processMSG(UA_Server *server, UA_SecureChannel *channel, /* Decode the request */ UA_Request request; - retval = UA_decodeBinary(msg, &offset, &request, requestType, server->config.customDataTypes); + retval = UA_decodeBinaryInternal(msg, &offset, &request, + requestType, server->config.customDataTypes); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, "Could not decode the request with StatusCode %s", @@ -25540,7 +24993,7 @@ processMSG(UA_Server *server, UA_SecureChannel *channel, "See the 'verifyRequestTimestamp' setting."); if(server->config.verifyRequestTimestamp <= UA_RULEHANDLING_ABORT) { retval = sendServiceFault(channel, requestId, requestHeader->requestHandle, - responseType, UA_STATUSCODE_BADINVALIDTIMESTAMP); + UA_STATUSCODE_BADINVALIDTIMESTAMP); UA_clear(&request, requestType); return retval; } @@ -25550,9 +25003,11 @@ processMSG(UA_Server *server, UA_SecureChannel *channel, #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Set the authenticationToken from the create session request to help * fuzzing cover more lines */ - UA_NodeId_clear(&requestHeader->authenticationToken); - if(!UA_NodeId_isNull(&unsafe_fuzz_authenticationToken)) + if(!UA_NodeId_isNull(&unsafe_fuzz_authenticationToken) && + !UA_NodeId_isNull(&requestHeader->authenticationToken)) { + UA_NodeId_clear(&requestHeader->authenticationToken); UA_NodeId_copy(&unsafe_fuzz_authenticationToken, &requestHeader->authenticationToken); + } #endif /* Prepare the respone and process the request */ @@ -25560,7 +25015,7 @@ processMSG(UA_Server *server, UA_SecureChannel *channel, UA_init(&response, responseType); response.responseHeader.requestHandle = requestHeader->requestHandle; retval = processMSGDecoded(server, channel, requestId, service, &request, requestType, - &response, responseType, sessionRequired); + &response, responseType, sessionRequired, counterOffset); /* Clean up */ UA_clear(&request, requestType); @@ -25569,7 +25024,7 @@ processMSG(UA_Server *server, UA_SecureChannel *channel, } /* Takes decoded messages starting at the nodeid of the content type. */ -static void +static UA_StatusCode processSecureChannelMessage(void *application, UA_SecureChannel *channel, UA_MessageType messagetype, UA_UInt32 requestId, UA_ByteString *message) { @@ -25583,7 +25038,7 @@ processSecureChannelMessage(void *application, UA_SecureChannel *channel, break; case UA_MESSAGETYPE_OPN: UA_LOG_TRACE_CHANNEL(&server->config.logger, channel, "Process an OPN message"); - retval = decryptProcessOPN(server, channel, message); + retval = processOPN(server, channel, requestId, message); break; case UA_MESSAGETYPE_MSG: UA_LOG_TRACE_CHANNEL(&server->config.logger, channel, "Process a MSG"); @@ -25603,7 +25058,7 @@ processSecureChannelMessage(void *application, UA_SecureChannel *channel, UA_LOG_INFO_CHANNEL(&server->config.logger, channel, "Processing the message failed. Channel already closed " "with StatusCode %s. ", UA_StatusCode_name(retval)); - return; + return retval; } UA_LOG_INFO_CHANNEL(&server->config.logger, channel, @@ -25627,6 +25082,8 @@ processSecureChannelMessage(void *application, UA_SecureChannel *channel, break; } } + + return retval; } void @@ -25673,31 +25130,13 @@ UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, connection->close(connection); } -#if UA_MULTITHREADING >= 200 -static void -deleteConnection(UA_Server *server, UA_Connection *connection) { - connection->free(connection); -} -#endif - void UA_Server_removeConnection(UA_Server *server, UA_Connection *connection) { UA_Connection_detachSecureChannel(connection); -#if UA_MULTITHREADING >= 200 - UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_malloc(sizeof(UA_DelayedCallback)); - if(!dc) - return; /* Malloc cannot fail on OS's that support multithreading. They - * rather kill the process. */ - dc->callback = (UA_ApplicationCallback)deleteConnection; - dc->application = server; - dc->data = connection; - UA_WorkQueue_enqueueDelayed(&server->workQueue, dc); -#else connection->free(connection); -#endif } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_utils.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_utils.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -25712,109 +25151,29 @@ UA_Server_removeConnection(UA_Server *server, UA_Connection *connection) { */ -#define UA_MAX_TREE_RECURSE 50 /* How deep up/down the tree do we recurse at most? */ +const UA_DataType * +UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId) { + return UA_findDataTypeWithCustom(typeId, server->config.customDataTypes); +} /********************************/ /* Information Model Operations */ /********************************/ -/* Keeps track of already visited nodes to detect circular references */ -struct ref_history { - struct ref_history *parent; /* the previous element */ - const UA_NodeId *id; /* the id of the node at this depth */ - UA_UInt16 depth; -}; - -static UA_Boolean -isNodeInTreeNoCircular(UA_Server *server, const UA_NodeId *leafNode, const UA_NodeId *nodeToFind, - struct ref_history *visitedRefs, const UA_NodeId *referenceTypeIds, - size_t referenceTypeIdsSize) { - if(UA_NodeId_equal(nodeToFind, leafNode)) - return true; - - if(visitedRefs->depth >= UA_MAX_TREE_RECURSE) - return false; - - const UA_Node *node = UA_NODESTORE_GET(server, leafNode); - if(!node) - return false; - - for(size_t i = 0; i < node->referencesSize; ++i) { - UA_NodeReferenceKind *refs = &node->references[i]; - /* Search upwards in the tree */ - if(!refs->isInverse) - continue; - - /* Consider only the indicated reference types */ - UA_Boolean match = false; - for(size_t j = 0; j < referenceTypeIdsSize; ++j) { - if(UA_NodeId_equal(&refs->referenceTypeId, &referenceTypeIds[j])) { - match = true; - break; - } - } - if(!match) - continue; - - /* Match the targets or recurse */ - for(size_t j = 0; j < refs->refTargetsSize; ++j) { - /* Check if we already have seen the referenced node and skip to - * avoid endless recursion. Do this only at every 5th depth to save - * effort. Circular dependencies are rare and forbidden for most - * reference types. */ - if(visitedRefs->depth % 5 == 4) { - struct ref_history *last = visitedRefs; - UA_Boolean skip = false; - while(!skip && last) { - if(UA_NodeId_equal(last->id, &refs->refTargets[j].targetId.nodeId)) - skip = true; - last = last->parent; - } - if(skip) - continue; - } - - /* Stack-allocate the visitedRefs structure for the next depth */ - struct ref_history nextVisitedRefs = {visitedRefs, &refs->refTargets[j].targetId.nodeId, - (UA_UInt16)(visitedRefs->depth+1)}; - - /* Recurse */ - UA_Boolean foundRecursive = - isNodeInTreeNoCircular(server, &refs->refTargets[j].targetId.nodeId, nodeToFind, - &nextVisitedRefs, referenceTypeIds, referenceTypeIdsSize); - if(foundRecursive) { - UA_NODESTORE_RELEASE(server, node); - return true; - } - } - } - - UA_NODESTORE_RELEASE(server, node); - return false; -} - -UA_Boolean -isNodeInTree(UA_Server *server, const UA_NodeId *leafNode, const UA_NodeId *nodeToFind, - const UA_NodeId *referenceTypeIds, size_t referenceTypeIdsSize) { - struct ref_history visitedRefs = {NULL, leafNode, 0}; - return isNodeInTreeNoCircular(server, leafNode, nodeToFind, &visitedRefs, - referenceTypeIds, referenceTypeIdsSize); -} - const UA_Node * -getNodeType(UA_Server *server, const UA_Node *node) { +getNodeType(UA_Server *server, const UA_NodeHead *head) { /* The reference to the parent is different for variable and variabletype */ - UA_NodeId parentRef; + UA_Byte parentRefIndex; UA_Boolean inverse; UA_NodeClass typeNodeClass; - switch(node->nodeClass) { + switch(head->nodeClass) { case UA_NODECLASS_OBJECT: - parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); + parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION; inverse = false; typeNodeClass = UA_NODECLASS_OBJECTTYPE; break; case UA_NODECLASS_VARIABLE: - parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); + parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION; inverse = false; typeNodeClass = UA_NODECLASS_VARIABLETYPE; break; @@ -25822,69 +25181,72 @@ getNodeType(UA_Server *server, const UA_Node *node) { case UA_NODECLASS_VARIABLETYPE: case UA_NODECLASS_REFERENCETYPE: case UA_NODECLASS_DATATYPE: - parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); + parentRefIndex = UA_REFERENCETYPEINDEX_HASSUBTYPE; inverse = true; - typeNodeClass = node->nodeClass; + typeNodeClass = head->nodeClass; break; default: return NULL; } /* Return the first matching candidate */ - for(size_t i = 0; i < node->referencesSize; ++i) { - if(node->references[i].isInverse != inverse) - continue; - if(!UA_NodeId_equal(&node->references[i].referenceTypeId, &parentRef)) + for(size_t i = 0; i < head->referencesSize; ++i) { + UA_NodeReferenceKind *rk = &head->references[i]; + if(rk->isInverse != inverse) continue; - UA_assert(node->references[i].refTargetsSize> 0); - const UA_NodeId *targetId = &node->references[i].refTargets[0].targetId.nodeId; - const UA_Node *type = UA_NODESTORE_GET(server, targetId); - if(!type) + if(rk->referenceTypeIndex != parentRefIndex) continue; - if(type->nodeClass == typeNodeClass) - return type; - UA_NODESTORE_RELEASE(server, type); + + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + const UA_Node *type = UA_NODESTORE_GETFROMREF(server, t->targetId); + if(!type) + continue; + if(type->head.nodeClass == typeNodeClass) + return type; /* Don't release the node that is returned */ + UA_NODESTORE_RELEASE(server, type); + } } return NULL; } UA_Boolean -UA_Node_hasSubTypeOrInstances(const UA_Node *node) { - const UA_NodeId hasSubType = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); - const UA_NodeId hasTypeDefinition = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); - for(size_t i = 0; i < node->referencesSize; ++i) { - if(node->references[i].isInverse == false && - UA_NodeId_equal(&node->references[i].referenceTypeId, &hasSubType)) +UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head) { + for(size_t i = 0; i < head->referencesSize; ++i) { + if(head->references[i].isInverse == false && + head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASSUBTYPE) return true; - if(node->references[i].isInverse == true && - UA_NodeId_equal(&node->references[i].referenceTypeId, &hasTypeDefinition)) + if(head->references[i].isInverse == true && + head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASTYPEDEFINITION) return true; } return false; } -static const UA_NodeId hasInterfaceNodeId = - {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASINTERFACE}}; - UA_StatusCode getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode, UA_NodeId **typeHierarchy, size_t *typeHierarchySize) { + UA_ReferenceTypeSet reftypes_subtype = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); UA_ExpandedNodeId *subTypes = NULL; size_t subTypesSize = 0; - UA_StatusCode retval = browseRecursive(server, 1, typeNode, 1, &subtypeId, - UA_BROWSEDIRECTION_INVERSE, false, - &subTypesSize, &subTypes); + UA_StatusCode retval = browseRecursive(server, 1, typeNode, + UA_BROWSEDIRECTION_INVERSE, + &reftypes_subtype, UA_NODECLASS_UNSPECIFIED, + false, &subTypesSize, &subTypes); if(retval != UA_STATUSCODE_GOOD) return retval; UA_assert(subTypesSize < 1000); + UA_ReferenceTypeSet reftypes_interface = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE); UA_ExpandedNodeId *interfaces = NULL; size_t interfacesSize = 0; - retval = browseRecursive(server, 1, typeNode, 1, &hasInterfaceNodeId, - UA_BROWSEDIRECTION_FORWARD, false, - &interfacesSize, &interfaces); + retval = browseRecursive(server, 1, typeNode, UA_BROWSEDIRECTION_FORWARD, + &reftypes_interface, UA_NODECLASS_UNSPECIFIED, + false, &interfacesSize, &interfaces); if(retval != UA_STATUSCODE_GOOD) { UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]); return retval; @@ -25927,6 +25289,124 @@ getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode, return UA_STATUSCODE_GOOD; } +UA_StatusCode +getAllInterfaceChildNodeIds(UA_Server *server, const UA_NodeId *objectNode, + const UA_NodeId *objectTypeNode, + UA_NodeId **interfaceChildNodes, + size_t *interfaceChildNodesSize) { + if(interfaceChildNodesSize == NULL || interfaceChildNodes == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + *interfaceChildNodesSize = 0; + *interfaceChildNodes = NULL; + + UA_ExpandedNodeId *hasInterfaceCandidates = NULL; + size_t hasInterfaceCandidatesSize = 0; + UA_ReferenceTypeSet reftypes_subtype = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); + + UA_StatusCode retval = + browseRecursive(server, 1, objectTypeNode, UA_BROWSEDIRECTION_INVERSE, + &reftypes_subtype, UA_NODECLASS_OBJECTTYPE, + true, &hasInterfaceCandidatesSize, + &hasInterfaceCandidates); + + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* The interface could also have been added manually before calling UA_Server_addNode_finish + * This can be handled by adding the object node as a start node for the HasInterface lookup */ + UA_ExpandedNodeId *resizedHasInterfaceCandidates = (UA_ExpandedNodeId*) + UA_realloc(hasInterfaceCandidates, + (hasInterfaceCandidatesSize + 1) * sizeof(UA_ExpandedNodeId)); + + if(!resizedHasInterfaceCandidates) { + if(hasInterfaceCandidates) + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + hasInterfaceCandidates = resizedHasInterfaceCandidates; + hasInterfaceCandidatesSize += 1; + UA_ExpandedNodeId_init(&hasInterfaceCandidates[hasInterfaceCandidatesSize - 1]); + + UA_ExpandedNodeId_init(&hasInterfaceCandidates[hasInterfaceCandidatesSize - 1]); + UA_NodeId_copy(objectNode, &hasInterfaceCandidates[hasInterfaceCandidatesSize - 1].nodeId); + + size_t outputIndex = 0; + + for(size_t i = 0; i < hasInterfaceCandidatesSize; ++i) { + UA_ReferenceTypeSet reftypes_interface = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE); + UA_ExpandedNodeId *interfaceChildren = NULL; + size_t interfacesChildrenSize = 0; + retval = browseRecursive(server, 1, &hasInterfaceCandidates[i].nodeId, + UA_BROWSEDIRECTION_FORWARD, + &reftypes_interface, UA_NODECLASS_OBJECTTYPE, + false, &interfacesChildrenSize, &interfaceChildren); + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + if(*interfaceChildNodesSize) { + UA_Array_delete(*interfaceChildNodes, *interfaceChildNodesSize, + &UA_TYPES[UA_TYPES_NODEID]); + *interfaceChildNodesSize = 0; + } + return retval; + } + + UA_assert(interfacesChildrenSize < 1000); + + if(interfacesChildrenSize == 0) { + continue; + } + + if(!*interfaceChildNodes) { + *interfaceChildNodes = (UA_NodeId*) + UA_calloc(interfacesChildrenSize, sizeof(UA_NodeId)); + *interfaceChildNodesSize = interfacesChildrenSize; + + if(!*interfaceChildNodes) { + UA_Array_delete(interfaceChildren, interfacesChildrenSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + } else { + UA_NodeId *resizedInterfaceChildNodes = (UA_NodeId*) + UA_realloc(*interfaceChildNodes, + ((*interfaceChildNodesSize + interfacesChildrenSize) * sizeof(UA_NodeId))); + + if(!resizedInterfaceChildNodes) { + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(interfaceChildren, interfacesChildrenSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + const size_t oldSize = *interfaceChildNodesSize; + *interfaceChildNodesSize += interfacesChildrenSize; + *interfaceChildNodes = resizedInterfaceChildNodes; + + for(size_t j = oldSize; j < *interfaceChildNodesSize; ++j) + UA_NodeId_init(&(*interfaceChildNodes)[j]); + } + + for(size_t j = 0; j < interfacesChildrenSize; j++) { + (*interfaceChildNodes)[outputIndex++] = interfaceChildren[j].nodeId; + } + + UA_assert(*interfaceChildNodesSize < 1000); + UA_Array_delete(interfaceChildren, interfacesChildrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + } + + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + + return UA_STATUSCODE_GOOD; +} + /* For mulithreading: make a copy of the node, edit and replace. * For singlethreading: edit the original */ UA_StatusCode @@ -26083,7 +25563,7 @@ const UA_ViewAttributes UA_ViewAttributes_default = { }; -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_discovery.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_discovery.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -26132,31 +25612,31 @@ register_server_with_discovery_server(UA_Server *server, request.server.serverNames = &server->config.applicationDescription.applicationName; request.server.serverNamesSize = 1; - /* Copy the discovery urls from the server config and the network layers*/ + /* Mirror the discovery urls from the server config and the network layers */ size_t config_discurls = server->config.applicationDescription.discoveryUrlsSize; size_t nl_discurls = server->config.networkLayersSize; size_t total_discurls = config_discurls + nl_discurls; - UA_STACKARRAY(UA_String, urlsBuf, total_discurls); - request.server.discoveryUrls = urlsBuf; - request.server.discoveryUrlsSize = total_discurls; + request.server.discoveryUrls = (UA_String*) + UA_Array_new(total_discurls, &UA_TYPES[UA_TYPES_STRING]); + if(!request.server.discoveryUrls) + return UA_STATUSCODE_BADOUTOFMEMORY; for(size_t i = 0; i < config_discurls; ++i) request.server.discoveryUrls[i] = server->config.applicationDescription.discoveryUrls[i]; - /* TODO: Add nl only if discoveryUrl not already present */ for(size_t i = 0; i < nl_discurls; ++i) { UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; request.server.discoveryUrls[config_discurls + i] = nl->discoveryUrl; } + request.server.discoveryUrlsSize = total_discurls; #ifdef UA_ENABLE_DISCOVERY_MULTICAST request.discoveryConfigurationSize = 1; request.discoveryConfiguration = UA_ExtensionObject_new(); - UA_ExtensionObject_init(&request.discoveryConfiguration[0]); // Set to NODELETE so that we can just use a pointer to the mdns config - request.discoveryConfiguration[0].encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; - request.discoveryConfiguration[0].content.decoded.type = &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION]; - request.discoveryConfiguration[0].content.decoded.data = &server->config.discovery.mdns; + UA_ExtensionObject_setValueNoDelete(request.discoveryConfiguration, + &server->config.mdnsConfig, + &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION]); #endif // First try with RegisterServer2, if that isn't implemented, use RegisterServer @@ -26169,8 +25649,8 @@ register_server_with_discovery_server(UA_Server *server, UA_Array_delete(request.discoveryConfiguration, request.discoveryConfigurationSize, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); - request.discoveryConfiguration = NULL; - request.discoveryConfigurationSize = 0; + if(total_discurls > 0) + UA_free(request.server.discoveryUrls); if(serviceResult == UA_STATUSCODE_BADNOTIMPLEMENTED || serviceResult == UA_STATUSCODE_BADSERVICEUNSUPPORTED) { @@ -26204,25 +25684,25 @@ register_server_with_discovery_server(UA_Server *server, UA_StatusCode UA_Server_register_discovery(UA_Server *server, UA_Client *client, const char* semaphoreFilePath) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = register_server_with_discovery_server(server, client, false, semaphoreFilePath); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } UA_StatusCode UA_Server_unregister_discovery(UA_Server *server, UA_Client *client) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = register_server_with_discovery_server(server, client, true, NULL); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } #endif /* UA_ENABLE_DISCOVERY */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_server_async.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_server_async.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -26247,9 +25727,11 @@ UA_AsyncManager_sendAsyncResponse(UA_AsyncManager *am, UA_Server *server, UA_AsyncResponse *ar) { /* Get the session */ UA_StatusCode res = UA_STATUSCODE_GOOD; - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_Session* session = UA_Server_getSessionById(server, &ar->sessionId); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); + UA_SecureChannel* channel = NULL; + UA_ResponseHeader *responseHeader = NULL; if(!session) { res = UA_STATUSCODE_BADSESSIONIDINVALID; UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, @@ -26258,7 +25740,7 @@ UA_AsyncManager_sendAsyncResponse(UA_AsyncManager *am, UA_Server *server, } /* Check the channel */ - UA_SecureChannel* channel = session->header.channel; + channel = session->header.channel; if(!channel) { res = UA_STATUSCODE_BADSECURECHANNELCLOSED; UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, @@ -26267,7 +25749,7 @@ UA_AsyncManager_sendAsyncResponse(UA_AsyncManager *am, UA_Server *server, } /* Okay, here we go, send the UA_CallResponse */ - UA_ResponseHeader *responseHeader = (UA_ResponseHeader*) + responseHeader = (UA_ResponseHeader*) &ar->response.callResponse.responseHeader; responseHeader->requestHandle = ar->requestHandle; res = sendResponse(server, session, channel, ar->requestId, @@ -26311,11 +25793,11 @@ static void processAsyncResults(UA_Server *server, void *data) { UA_AsyncManager *am = &server->asyncManager; while(true) { - UA_LOCK(am->queueLock); + UA_LOCK(&am->queueLock); UA_AsyncOperation *ao = TAILQ_FIRST(&am->resultQueue); if(ao) TAILQ_REMOVE(&am->resultQueue, ao, pointers); - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); if(!ao) break; UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, @@ -26336,7 +25818,7 @@ checkTimeouts(UA_Server *server, void *_) { UA_AsyncManager *am = &server->asyncManager; const UA_DateTime tNow = UA_DateTime_now(); - UA_LOCK(am->queueLock); + UA_LOCK(&am->queueLock); /* Loop over the queue of dispatched ops */ UA_AsyncOperation *op = NULL, *op_tmp = NULL; @@ -26367,7 +25849,7 @@ checkTimeouts(UA_Server *server, void *_) { "Operation was removed due to a timeout"); } - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); /* Integrate async results and send out complete responses */ processAsyncResults(server, NULL); @@ -26380,7 +25862,7 @@ UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server) { TAILQ_INIT(&am->newQueue); TAILQ_INIT(&am->dispatchedQueue); TAILQ_INIT(&am->resultQueue); - UA_LOCK_INIT(am->queueLock); + UA_LOCK_INIT(&am->queueLock); /* Add a regular callback for cleanup and sending finished responses at a * 100s interval. */ @@ -26390,25 +25872,25 @@ UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server) { void UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server) { - UA_Server_removeCallback(server, am->checkTimeoutCallbackId); + removeCallback(server, am->checkTimeoutCallbackId); - UA_AsyncOperation *ar; + UA_AsyncOperation *ar, *ar_tmp; /* Clean up queues */ - UA_LOCK(am->queueLock); - while((ar = TAILQ_FIRST(&am->newQueue))) { - TAILQ_REMOVE(&am->resultQueue, ar, pointers); + UA_LOCK(&am->queueLock); + TAILQ_FOREACH_SAFE(ar, &am->newQueue, pointers, ar_tmp) { + TAILQ_REMOVE(&am->newQueue, ar, pointers); UA_AsyncOperation_delete(ar); } - while((ar = TAILQ_FIRST(&am->dispatchedQueue))) { - TAILQ_REMOVE(&am->resultQueue, ar, pointers); + TAILQ_FOREACH_SAFE(ar, &am->dispatchedQueue, pointers, ar_tmp) { + TAILQ_REMOVE(&am->dispatchedQueue, ar, pointers); UA_AsyncOperation_delete(ar); } - while((ar = TAILQ_FIRST(&am->resultQueue))) { + TAILQ_FOREACH_SAFE(ar, &am->resultQueue, pointers, ar_tmp) { TAILQ_REMOVE(&am->resultQueue, ar, pointers); UA_AsyncOperation_delete(ar); } - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); /* Remove responses */ UA_AsyncResponse *current, *temp; @@ -26417,7 +25899,7 @@ UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server) { } /* Delete all locks */ - UA_LOCK_DESTROY(am->queueLock); + UA_LOCK_DESTROY(&am->queueLock); } UA_StatusCode @@ -26491,11 +25973,11 @@ UA_AsyncManager_createAsyncOp(UA_AsyncManager *am, UA_Server *server, ao->index = opIndex; ao->parent = ar; - UA_LOCK(am->queueLock); + UA_LOCK(&am->queueLock); TAILQ_INSERT_TAIL(&am->newQueue, ao, pointers); am->opsCount++; ar->opCountdown++; - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); if(server->config.asyncOperationNotifyCallback) server->config.asyncOperationNotifyCallback(server); @@ -26512,7 +25994,7 @@ UA_Server_getAsyncOperationNonBlocking(UA_Server *server, UA_AsyncOperationType UA_Boolean bRV = false; *type = UA_ASYNCOPERATIONTYPE_INVALID; - UA_LOCK(am->queueLock); + UA_LOCK(&am->queueLock); UA_AsyncOperation *ao = TAILQ_FIRST(&am->newQueue); if(ao) { TAILQ_REMOVE(&am->newQueue, ao, pointers); @@ -26524,18 +26006,11 @@ UA_Server_getAsyncOperationNonBlocking(UA_Server *server, UA_AsyncOperationType *timeout = ao->parent->timeout; bRV = true; } - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); return bRV; } -UA_Boolean -UA_Server_getAsyncOperation(UA_Server *server, UA_AsyncOperationType *type, - const UA_AsyncOperationRequest **request, - void **context) { - return UA_Server_getAsyncOperationNonBlocking(server, type, request, context, NULL); -} - /* Worker submits Method Call Response */ void UA_Server_setAsyncOperationResult(UA_Server *server, @@ -26551,7 +26026,7 @@ UA_Server_setAsyncOperationResult(UA_Server *server, return; } - UA_LOCK(am->queueLock); + UA_LOCK(&am->queueLock); /* See if the operation is still in the dispatched queue. Otherwise it has * been removed due to a timeout. @@ -26570,7 +26045,7 @@ UA_Server_setAsyncOperationResult(UA_Server *server, if(!found) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_Server_SetAsyncMethodResult: The operation has timed out"); - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); return; } @@ -26587,7 +26062,7 @@ UA_Server_setAsyncOperationResult(UA_Server *server, TAILQ_REMOVE(&am->dispatchedQueue, ao, pointers); TAILQ_INSERT_TAIL(&am->resultQueue, ao, pointers); - UA_UNLOCK(am->queueLock); + UA_UNLOCK(&am->queueLock); UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "Set the result from the worker thread"); @@ -26600,10 +26075,9 @@ UA_Server_setAsyncOperationResult(UA_Server *server, static UA_StatusCode setMethodNodeAsync(UA_Server *server, UA_Session *session, UA_Node *node, UA_Boolean *isAsync) { - UA_MethodNode *method = (UA_MethodNode*)node; - if(method->nodeClass != UA_NODECLASS_METHOD) + if(node->head.nodeClass != UA_NODECLASS_METHOD) return UA_STATUSCODE_BADNODECLASSINVALID; - method->async = *isAsync; + node->methodNode.async = *isAsync; return UA_STATUSCODE_GOOD; } @@ -26649,7 +26123,7 @@ UA_Server_processServiceOperationsAsync(UA_Server *server, UA_Session *session, #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_networkmessage.c" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -26660,8 +26134,8 @@ UA_Server_processServiceOperationsAsync(UA_Server *server, UA_Session *session, */ -#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ +#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ const UA_Byte NM_VERSION_MASK = 15; const UA_Byte NM_PUBLISHER_ID_ENABLED_MASK = 16; @@ -26705,21 +26179,34 @@ static UA_Boolean UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetM UA_StatusCode UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer){ UA_StatusCode rv = UA_STATUSCODE_GOOD; - for (size_t i = 0; i < buffer->offsetsSize; ++i) { + for(size_t i = 0; i < buffer->offsetsSize; ++i) { + UA_NetworkMessageOffset *nmo = &buffer->offsets[i]; const UA_Byte *bufEnd = &buffer->buffer.data[buffer->buffer.length]; - UA_Byte *bufPos = &buffer->buffer.data[buffer->offsets[i].offset]; - switch (buffer->offsets[i].contentType) { + UA_Byte *bufPos = &buffer->buffer.data[nmo->offset]; + switch(nmo->contentType) { case UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER: - rv = UA_UInt16_encodeBinary((UA_UInt16 *) buffer->offsets[i].offsetData.value.value->value.data, &bufPos, bufEnd); - break; case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER: - rv = UA_UInt16_encodeBinary((UA_UInt16 *) buffer->offsets[i].offsetData.value.value->value.data, &bufPos, bufEnd); + rv = UA_UInt16_encodeBinary((UA_UInt16 *)nmo->offsetData.value.value->value.data, &bufPos, bufEnd); + if(*((UA_UInt16 *)nmo->offsetData.value.value->value.data) < UA_UINT16_MAX){ + (*((UA_UInt16 *)nmo->offsetData.value.value->value.data))++; + } else { + (*((UA_UInt16 *)nmo->offsetData.value.value->value.data)) = 0; + } break; case UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE: - rv = UA_DataValue_encodeBinary(buffer->offsets[i].offsetData.value.value, &bufPos, bufEnd); + rv = UA_DataValue_encodeBinary(nmo->offsetData.value.value, + &bufPos, bufEnd); break; case UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT: - rv = UA_Variant_encodeBinary(&buffer->offsets[i].offsetData.value.value->value, &bufPos, bufEnd); + rv = UA_Variant_encodeBinary(&nmo->offsetData.value.value->value, + &bufPos, bufEnd); + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW: + rv = UA_encodeBinaryInternal(nmo->offsetData.value.value->value.data, + nmo->offsetData.value.value->value.type, + &bufPos, &bufEnd, NULL, NULL); + break; + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING: break; default: return UA_STATUSCODE_BADNOTSUPPORTED; @@ -26729,8 +26216,99 @@ UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer){ } UA_StatusCode -UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, - const UA_Byte *bufEnd) { +UA_NetworkMessage_updateBufferedNwMessage(UA_NetworkMessageOffsetBuffer *buffer, + const UA_ByteString *src, size_t *bufferPosition){ + UA_StatusCode rv = UA_STATUSCODE_GOOD; + size_t payloadCounter = 0; + size_t offset = 0; + UA_DataSetMessage* dsm = buffer->nm->payload.dataSetPayload.dataSetMessages; //Considering one DSM in RT TODO: Clarify multiple DSM + UA_DataSetMessageHeader header; + size_t smallestRawOffset = UA_UINT32_MAX; + + for (size_t i = 0; i < buffer->offsetsSize; ++i) { + offset = buffer->offsets[i].offset + *bufferPosition; + switch (buffer->offsets[i].contentType) { + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING: + rv = UA_DataSetMessageHeader_decodeBinary(src, &offset, &header); + if(rv != UA_STATUSCODE_GOOD) + return rv; + break; + case UA_PUBSUB_OFFSETTYPE_PUBLISHERID: + switch (buffer->nm->publisherIdType) { + case UA_PUBLISHERDATATYPE_BYTE: + rv = UA_Byte_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdByte)); + break; + case UA_PUBLISHERDATATYPE_UINT16: + rv = UA_UInt16_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdUInt16)); + break; + case UA_PUBLISHERDATATYPE_UINT32: + rv = UA_UInt32_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdUInt32)); + break; + case UA_PUBLISHERDATATYPE_UINT64: + rv = UA_UInt64_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdUInt64)); + break; + default: + return UA_STATUSCODE_BADNOTSUPPORTED; + } + break; + case UA_PUBSUB_OFFSETTYPE_WRITERGROUPID: + rv = UA_UInt16_decodeBinary(src, &offset, &buffer->nm->groupHeader.writerGroupId); + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_DATASETWRITERID: + rv = UA_UInt16_decodeBinary(src, &offset, + &buffer->nm->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]); /* TODO */ + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER: + rv = UA_UInt16_decodeBinary(src, &offset, &buffer->nm->groupHeader.sequenceNumber); + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER: + rv = UA_UInt16_decodeBinary(src, &offset, &(dsm->header.dataSetMessageSequenceNr)); + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE: + rv = UA_DataValue_decodeBinary(src, &offset, + &(dsm->data.keyFrameData.dataSetFields[payloadCounter])); + UA_CHECK_STATUS(rv, return rv); + payloadCounter++; + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT: + rv = UA_Variant_decodeBinary(src, &offset, + &dsm->data.keyFrameData.dataSetFields[payloadCounter].value); + UA_CHECK_STATUS(rv, return rv); + dsm->data.keyFrameData.dataSetFields[payloadCounter].hasValue = true; + payloadCounter++; + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW: + /* We need only the start address of the raw fields */ + if (smallestRawOffset > offset){ + smallestRawOffset = offset; + dsm->data.keyFrameData.rawFields.data = &src->data[offset]; + dsm->data.keyFrameData.rawFields.length = buffer->rawMessageLength; + } + payloadCounter++; + break; + default: + return UA_STATUSCODE_BADNOTSUPPORTED; + } + } + //check if the frame is of type "raw" payload + if(smallestRawOffset != UA_UINT32_MAX){ + *bufferPosition = smallestRawOffset + buffer->rawMessageLength; + } else { + *bufferPosition = offset; + } + + return rv; +} + +static +UA_StatusCode +UA_NetworkMessageHeader_encodeBinary(const UA_NetworkMessage *src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + /* UADPVersion + UADP Flags */ UA_Byte v = src->version; if(src->publisherIdEnabled) @@ -26746,9 +26324,7 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, v |= NM_EXTENDEDFLAGS1_ENABLED_MASK; UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - + UA_CHECK_STATUS(rv, return rv); // ExtendedFlags1 if(UA_NetworkMessage_ExtendedFlags1Enabled(src)) { v = (UA_Byte)src->publisherIdType; @@ -26769,8 +26345,7 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, v |= NM_EXTENDEDFLAGS2_ENABLED_MASK; rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); // ExtendedFlags2 if(UA_NetworkMessage_ExtendedFlags2Enabled(src)) { @@ -26785,8 +26360,7 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, v |= NM_PROMOTEDFIELDS_ENABLED_MASK; rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } @@ -26817,89 +26391,99 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, rv = UA_STATUSCODE_BADINTERNALERROR; break; } - - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // DataSetClassId if(src->dataSetClassIdEnabled) { rv = UA_Guid_encodeBinary(&(src->dataSetClassId), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} - // Group Header - if(src->groupHeaderEnabled) { - v = 0; +static +UA_StatusCode +UA_GroupHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { - if(src->groupHeader.writerGroupIdEnabled) - v |= GROUP_HEADER_WRITER_GROUPID_ENABLED; + UA_Byte v = 0; - if(src->groupHeader.groupVersionEnabled) - v |= GROUP_HEADER_GROUP_VERSION_ENABLED; + if(src->groupHeader.writerGroupIdEnabled) + v |= GROUP_HEADER_WRITER_GROUPID_ENABLED; - if(src->groupHeader.networkMessageNumberEnabled) - v |= GROUP_HEADER_NM_NUMBER_ENABLED; + if(src->groupHeader.groupVersionEnabled) + v |= GROUP_HEADER_GROUP_VERSION_ENABLED; - if(src->groupHeader.sequenceNumberEnabled) - v |= GROUP_HEADER_SEQUENCE_NUMBER_ENABLED; + if(src->groupHeader.networkMessageNumberEnabled) + v |= GROUP_HEADER_NM_NUMBER_ENABLED; - rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + if(src->groupHeader.sequenceNumberEnabled) + v |= GROUP_HEADER_SEQUENCE_NUMBER_ENABLED; - if(src->groupHeader.writerGroupIdEnabled) { - rv = UA_UInt16_encodeBinary(&(src->groupHeader.writerGroupId), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); - if(src->groupHeader.groupVersionEnabled) { - rv = UA_UInt32_encodeBinary(&(src->groupHeader.groupVersion), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + if(src->groupHeader.writerGroupIdEnabled) { + rv = UA_UInt16_encodeBinary(&(src->groupHeader.writerGroupId), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } - if(src->groupHeader.networkMessageNumberEnabled) { - rv = UA_UInt16_encodeBinary(&(src->groupHeader.networkMessageNumber), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + if(src->groupHeader.groupVersionEnabled) { + rv = UA_UInt32_encodeBinary(&(src->groupHeader.groupVersion), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } - if(src->groupHeader.sequenceNumberEnabled) { - rv = UA_UInt16_encodeBinary(&(src->groupHeader.sequenceNumber), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + if(src->groupHeader.networkMessageNumberEnabled) { + rv = UA_UInt16_encodeBinary(&(src->groupHeader.networkMessageNumber), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); } - // Payload-Header - if(src->payloadHeaderEnabled) { - if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET) - return UA_STATUSCODE_BADNOTIMPLEMENTED; - - rv = UA_Byte_encodeBinary(&(src->payloadHeader.dataSetPayloadHeader.count), bufPos, bufEnd); + if(src->groupHeader.sequenceNumberEnabled) { + rv = UA_UInt16_encodeBinary(&(src->groupHeader.sequenceNumber), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} - if(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds == NULL) - return UA_STATUSCODE_BADENCODINGERROR; - - for(UA_Byte i = 0; i < src->payloadHeader.dataSetPayloadHeader.count; i++) { - rv = UA_UInt16_encodeBinary(&(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i]), - bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } +static +UA_StatusCode +UA_PayloadHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return UA_STATUSCODE_BADNOTIMPLEMENTED; + + UA_StatusCode rv = UA_Byte_encodeBinary(&(src->payloadHeader.dataSetPayloadHeader.count), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds == NULL) + return UA_STATUSCODE_BADENCODINGERROR; + + for(UA_Byte i = 0; i < src->payloadHeader.dataSetPayloadHeader.count; i++) { + rv = UA_UInt16_encodeBinary(&(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i]), + bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} +static +UA_StatusCode +UA_ExtendedNetworkMessageHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + UA_StatusCode rv = UA_STATUSCODE_GOOD; // Timestamp if(src->timestampEnabled) rv = UA_DateTime_encodeBinary(&(src->timestamp), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); // Picoseconds if(src->picosecondsEnabled) rv = UA_UInt16_encodeBinary(&(src->picoseconds), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); // PromotedFields if(src->promotedFieldsEnabled) { /* Size (calculate & encode) */ @@ -26907,56 +26491,95 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, for(UA_UInt16 i = 0; i < src->promotedFieldsSize; i++) pfSize = (UA_UInt16) (pfSize + UA_Variant_calcSizeBinary(&src->promotedFields[i])); rv |= UA_UInt16_encodeBinary(&pfSize, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); for (UA_UInt16 i = 0; i < src->promotedFieldsSize; i++) rv |= UA_Variant_encodeBinary(&(src->promotedFields[i]), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} - // SecurityHeader - if(src->securityEnabled) { - // SecurityFlags - v = 0; - if(src->securityHeader.networkMessageSigned) - v |= SECURITY_HEADER_NM_SIGNED; +static +UA_StatusCode +UA_SecurityHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + // SecurityFlags + UA_Byte v = 0; + if(src->securityHeader.networkMessageSigned) + v |= SECURITY_HEADER_NM_SIGNED; - if(src->securityHeader.networkMessageEncrypted) - v |= SECURITY_HEADER_NM_ENCRYPTED; + if(src->securityHeader.networkMessageEncrypted) + v |= SECURITY_HEADER_NM_ENCRYPTED; - if(src->securityHeader.securityFooterEnabled) - v |= SECURITY_HEADER_SEC_FOOTER_ENABLED; + if(src->securityHeader.securityFooterEnabled) + v |= SECURITY_HEADER_SEC_FOOTER_ENABLED; - if(src->securityHeader.forceKeyReset) - v |= SECURITY_HEADER_FORCE_KEY_RESET; + if(src->securityHeader.forceKeyReset) + v |= SECURITY_HEADER_FORCE_KEY_RESET; - rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // SecurityTokenId + rv = UA_UInt32_encodeBinary(&src->securityHeader.securityTokenId, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // NonceLength + UA_Byte nonceLength = (UA_Byte)src->securityHeader.messageNonce.length; + rv = UA_Byte_encodeBinary(&nonceLength, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // MessageNonce + for (size_t i = 0; i < src->securityHeader.messageNonce.length; i++) { + rv = UA_Byte_encodeBinary(&src->securityHeader.messageNonce.data[i], + bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // SecurityFooterSize + if(src->securityHeader.securityFooterEnabled) { + rv = UA_UInt16_encodeBinary(&src->securityHeader.securityFooterSize, + bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } - // SecurityTokenId - rv = UA_UInt32_encodeBinary(&src->securityHeader.securityTokenId, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + return UA_STATUSCODE_GOOD; +} - // NonceLength - rv = UA_Byte_encodeBinary(&src->securityHeader.nonceLength, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; +UA_StatusCode +UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { - // MessageNonce - for (UA_Byte i = 0; i < src->securityHeader.nonceLength; i++) { - rv = UA_Byte_encodeBinary(&(src->securityHeader.messageNonce.data[i]), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + UA_StatusCode rv = UA_NetworkMessageHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // Group Header + if(src->groupHeaderEnabled) { + rv = UA_GroupHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } - // SecurityFooterSize - if(src->securityHeader.securityFooterEnabled) { - rv = UA_UInt16_encodeBinary(&src->securityHeader.securityFooterSize, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + // Payload Header + if(src->payloadHeaderEnabled) { + rv = UA_PayloadHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); } + // Extended Network Message Header + rv = UA_ExtendedNetworkMessageHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // SecurityHeader + if(src->securityEnabled) { + rv = UA_SecurityHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + + +UA_StatusCode +UA_NetworkMessage_encodePayload(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + UA_StatusCode rv; + // Payload if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET) return UA_STATUSCODE_BADNOTIMPLEMENTED; @@ -26978,303 +26601,351 @@ UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, } rv = UA_UInt16_encodeBinary(&sz, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } } for(UA_Byte i = 0; i < count; i++) { rv = UA_DataSetMessage_encodeBinary(&(src->payload.dataSetPayload.dataSetMessages[i]), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_encodeFooters(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + if(src->securityEnabled) { // SecurityFooter if(src->securityHeader.securityFooterEnabled) { - for(UA_Byte i = 0; i < src->securityHeader.securityFooterSize; i++) { - rv = UA_Byte_encodeBinary(&(src->securityFooter.data[i]), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + for(size_t i = 0; i < src->securityHeader.securityFooterSize; i++) { + UA_StatusCode rv = UA_Byte_encodeBinary(&(src->securityFooter.data[i]), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); } } + } + return UA_STATUSCODE_GOOD; +} - // Signature - if(src->securityHeader.networkMessageSigned) { - rv = UA_ByteString_encodeBinary(&(src->signature), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } +UA_StatusCode +UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd, UA_Byte **dataToEncryptStart) { + + UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(dataToEncryptStart) { + *dataToEncryptStart = *bufPos; } + rv = UA_NetworkMessage_encodePayload(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_encodeFooters(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_NetworkMessage_decodeBinaryInternal(const UA_ByteString *src, size_t *offset, - UA_NetworkMessage* dst) { - memset(dst, 0, sizeof(UA_NetworkMessage)); - UA_Byte v = 0; - UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; +UA_StatusCode +UA_NetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + UA_Byte decoded = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); - dst->version = v & NM_VERSION_MASK; - - if((v & NM_PUBLISHER_ID_ENABLED_MASK) != 0) + dst->version = decoded & NM_VERSION_MASK; + + if((decoded & NM_PUBLISHER_ID_ENABLED_MASK) != 0) dst->publisherIdEnabled = true; - if((v & NM_GROUP_HEADER_ENABLED_MASK) != 0) + if((decoded & NM_GROUP_HEADER_ENABLED_MASK) != 0) dst->groupHeaderEnabled = true; - if((v & NM_PAYLOAD_HEADER_ENABLED_MASK) != 0) + if((decoded & NM_PAYLOAD_HEADER_ENABLED_MASK) != 0) dst->payloadHeaderEnabled = true; - - if((v & NM_EXTENDEDFLAGS1_ENABLED_MASK) != 0) { - v = 0; - rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; - dst->publisherIdType = (UA_PublisherIdDatatype)(v & NM_PUBLISHER_ID_MASK); - if((v & NM_DATASET_CLASSID_ENABLED_MASK) != 0) + if((decoded & NM_EXTENDEDFLAGS1_ENABLED_MASK) != 0) { + decoded = 0; + rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); + + dst->publisherIdType = (UA_PublisherIdDatatype)(decoded & NM_PUBLISHER_ID_MASK); + if((decoded & NM_DATASET_CLASSID_ENABLED_MASK) != 0) dst->dataSetClassIdEnabled = true; - if((v & NM_SECURITY_ENABLED_MASK) != 0) + if((decoded & NM_SECURITY_ENABLED_MASK) != 0) dst->securityEnabled = true; - if((v & NM_TIMESTAMP_ENABLED_MASK) != 0) + if((decoded & NM_TIMESTAMP_ENABLED_MASK) != 0) dst->timestampEnabled = true; - if((v & NM_PICOSECONDS_ENABLED_MASK) != 0) + if((decoded & NM_PICOSECONDS_ENABLED_MASK) != 0) dst->picosecondsEnabled = true; - if((v & NM_EXTENDEDFLAGS2_ENABLED_MASK) != 0) { - v = 0; - rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; + if((decoded & NM_EXTENDEDFLAGS2_ENABLED_MASK) != 0) { + decoded = 0; + rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); - if((v & NM_CHUNK_MESSAGE_MASK) != 0) + if((decoded & NM_CHUNK_MESSAGE_MASK) != 0) dst->chunkMessage = true; - if((v & NM_PROMOTEDFIELDS_ENABLED_MASK) != 0) + if((decoded & NM_PROMOTEDFIELDS_ENABLED_MASK) != 0) dst->promotedFieldsEnabled = true; - v = v & NM_NETWORK_MSG_TYPE_MASK; - v = (UA_Byte) (v >> NM_SHIFT_LEN); - dst->networkMessageType = (UA_NetworkMessageType)v; + decoded = decoded & NM_NETWORK_MSG_TYPE_MASK; + decoded = (UA_Byte) (decoded >> NM_SHIFT_LEN); + dst->networkMessageType = (UA_NetworkMessageType)decoded; } } if(dst->publisherIdEnabled) { switch (dst->publisherIdType) { - case UA_PUBLISHERDATATYPE_BYTE: - rv = UA_Byte_decodeBinary(src, offset, &(dst->publisherId.publisherIdByte)); - break; + case UA_PUBLISHERDATATYPE_BYTE: + rv = UA_Byte_decodeBinary(src, offset, &(dst->publisherId.publisherIdByte)); + break; - case UA_PUBLISHERDATATYPE_UINT16: - rv = UA_UInt16_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt16)); - break; + case UA_PUBLISHERDATATYPE_UINT16: + rv = UA_UInt16_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt16)); + break; - case UA_PUBLISHERDATATYPE_UINT32: - rv = UA_UInt32_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt32)); - break; + case UA_PUBLISHERDATATYPE_UINT32: + rv = UA_UInt32_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt32)); + break; - case UA_PUBLISHERDATATYPE_UINT64: - rv = UA_UInt64_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt64)); - break; + case UA_PUBLISHERDATATYPE_UINT64: + rv = UA_UInt64_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt64)); + break; - case UA_PUBLISHERDATATYPE_STRING: - rv = UA_String_decodeBinary(src, offset, &(dst->publisherId.publisherIdString)); - break; + case UA_PUBLISHERDATATYPE_STRING: + rv = UA_String_decodeBinary(src, offset, &(dst->publisherId.publisherIdString)); + break; - default: - rv = UA_STATUSCODE_BADINTERNALERROR; - break; + default: + rv = UA_STATUSCODE_BADINTERNALERROR; + break; } - - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } if(dst->dataSetClassIdEnabled) { rv = UA_Guid_decodeBinary(src, offset, &(dst->dataSetClassId)); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} - // GroupHeader - if(dst->groupHeaderEnabled) { - v = 0; - rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; - - if((v & GROUP_HEADER_WRITER_GROUPID_ENABLED) != 0) - dst->groupHeader.writerGroupIdEnabled = true; +static UA_StatusCode +UA_GroupHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + UA_Byte decoded = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); - if((v & GROUP_HEADER_GROUP_VERSION_ENABLED) != 0) - dst->groupHeader.groupVersionEnabled = true; + if((decoded & GROUP_HEADER_WRITER_GROUPID_ENABLED) != 0) + dst->groupHeader.writerGroupIdEnabled = true; - if((v & GROUP_HEADER_NM_NUMBER_ENABLED) != 0) - dst->groupHeader.networkMessageNumberEnabled = true; + if((decoded & GROUP_HEADER_GROUP_VERSION_ENABLED) != 0) + dst->groupHeader.groupVersionEnabled = true; - if((v & GROUP_HEADER_SEQUENCE_NUMBER_ENABLED) != 0) - dst->groupHeader.sequenceNumberEnabled = true; + if((decoded & GROUP_HEADER_NM_NUMBER_ENABLED) != 0) + dst->groupHeader.networkMessageNumberEnabled = true; - if(dst->groupHeader.writerGroupIdEnabled) { - rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.writerGroupId); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + if((decoded & GROUP_HEADER_SEQUENCE_NUMBER_ENABLED) != 0) + dst->groupHeader.sequenceNumberEnabled = true; - if(dst->groupHeader.groupVersionEnabled) { - rv = UA_UInt32_decodeBinary(src, offset, &dst->groupHeader.groupVersion); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } - - if(dst->groupHeader.networkMessageNumberEnabled) { - rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.networkMessageNumber); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } - - if(dst->groupHeader.sequenceNumberEnabled) { - rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.sequenceNumber); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + if(dst->groupHeader.writerGroupIdEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.writerGroupId); + UA_CHECK_STATUS(rv, return rv); + } + if(dst->groupHeader.groupVersionEnabled) { + rv = UA_UInt32_decodeBinary(src, offset, &dst->groupHeader.groupVersion); + UA_CHECK_STATUS(rv, return rv); + } + if(dst->groupHeader.networkMessageNumberEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.networkMessageNumber); + UA_CHECK_STATUS(rv, return rv); + } + if(dst->groupHeader.sequenceNumberEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.sequenceNumber); + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} - // Payload-Header - if(dst->payloadHeaderEnabled) { - if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET) - return UA_STATUSCODE_BADNOTIMPLEMENTED; +static UA_StatusCode +UA_PayloadHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { - rv = UA_Byte_decodeBinary(src, offset, &dst->payloadHeader.dataSetPayloadHeader.count); - if(rv != UA_STATUSCODE_GOOD) - return rv; + if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return UA_STATUSCODE_BADNOTIMPLEMENTED; - dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = - (UA_UInt16 *)UA_Array_new(dst->payloadHeader.dataSetPayloadHeader.count, - &UA_TYPES[UA_TYPES_UINT16]); - for (UA_Byte i = 0; i < dst->payloadHeader.dataSetPayloadHeader.count; i++) { - rv = UA_UInt16_decodeBinary(src, offset, - &dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i]); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &dst->payloadHeader.dataSetPayloadHeader.count); + UA_CHECK_STATUS(rv, return rv); + + dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = + (UA_UInt16 *)UA_Array_new(dst->payloadHeader.dataSetPayloadHeader.count, + &UA_TYPES[UA_TYPES_UINT16]); + for (UA_Byte i = 0; i < dst->payloadHeader.dataSetPayloadHeader.count; i++) { + rv = UA_UInt16_decodeBinary(src, offset, + &dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i]); + UA_CHECK_STATUS(rv, return rv); } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_ExtendedNetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + UA_StatusCode rv; // Timestamp if(dst->timestampEnabled) { rv = UA_DateTime_decodeBinary(src, offset, &(dst->timestamp)); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, goto error); } // Picoseconds if(dst->picosecondsEnabled) { rv = UA_UInt16_decodeBinary(src, offset, &(dst->picoseconds)); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, goto error); } - // PromotedFields + // PromotedFields if(dst->promotedFieldsEnabled) { // Size UA_UInt16 promotedFieldsSize = 0; rv = UA_UInt16_decodeBinary(src, offset, &promotedFieldsSize); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, goto error); // promotedFieldsSize: here size in Byte, not the number of objects! if(promotedFieldsSize > 0) { - // store offset, later compared with promotedFieldsSize + // store offset, later compared with promotedFieldsSize size_t offsetEnd = (*offset) + promotedFieldsSize; unsigned int counter = 0; do { if(counter == 0) { dst->promotedFields = (UA_Variant*)UA_malloc(UA_TYPES[UA_TYPES_VARIANT].memSize); + UA_CHECK_MEM(dst->promotedFields, + return UA_STATUSCODE_BADOUTOFMEMORY); // set promotedFieldsSize to the number of objects dst->promotedFieldsSize = (UA_UInt16) (counter + 1); } else { dst->promotedFields = (UA_Variant*) UA_realloc(dst->promotedFields, - UA_TYPES[UA_TYPES_VARIANT].memSize * (counter + 1)); + (size_t) UA_TYPES[UA_TYPES_VARIANT].memSize * (counter + 1)); + UA_CHECK_MEM(dst->promotedFields, + return UA_STATUSCODE_BADOUTOFMEMORY); // set promotedFieldsSize to the number of objects dst->promotedFieldsSize = (UA_UInt16) (counter + 1); } UA_Variant_init(&dst->promotedFields[counter]); rv = UA_Variant_decodeBinary(src, offset, &dst->promotedFields[counter]); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, goto error); + counter++; } while ((*offset) < offsetEnd); } } + return UA_STATUSCODE_GOOD; - // SecurityHeader - if(dst->securityEnabled) { - // SecurityFlags - v = 0; - rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; +error: + if (dst->promotedFields) { + UA_free(dst->promotedFields); + } + return rv; +} - if((v & SECURITY_HEADER_NM_SIGNED) != 0) - dst->securityHeader.networkMessageSigned = true; +static UA_StatusCode +UA_SecurityHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + UA_Byte decoded = 0; + // SecurityFlags + decoded = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); - if((v & SECURITY_HEADER_NM_ENCRYPTED) != 0) - dst->securityHeader.networkMessageEncrypted = true; + if((decoded & SECURITY_HEADER_NM_SIGNED) != 0) + dst->securityHeader.networkMessageSigned = true; - if((v & SECURITY_HEADER_SEC_FOOTER_ENABLED) != 0) - dst->securityHeader.securityFooterEnabled = true; + if((decoded & SECURITY_HEADER_NM_ENCRYPTED) != 0) + dst->securityHeader.networkMessageEncrypted = true; - if((v & SECURITY_HEADER_FORCE_KEY_RESET) != 0) - dst->securityHeader.forceKeyReset = true; + if((decoded & SECURITY_HEADER_SEC_FOOTER_ENABLED) != 0) + dst->securityHeader.securityFooterEnabled = true; - // SecurityTokenId - rv = UA_UInt32_decodeBinary(src, offset, &dst->securityHeader.securityTokenId); - if(rv != UA_STATUSCODE_GOOD) - return rv; + if((decoded & SECURITY_HEADER_FORCE_KEY_RESET) != 0) + dst->securityHeader.forceKeyReset = true; - // NonceLength - rv = UA_Byte_decodeBinary(src, offset, &dst->securityHeader.nonceLength); - if(rv != UA_STATUSCODE_GOOD) - return rv; + // SecurityTokenId + rv = UA_UInt32_decodeBinary(src, offset, &dst->securityHeader.securityTokenId); + UA_CHECK_STATUS(rv, return rv); - // MessageNonce - if(dst->securityHeader.nonceLength > 0) { - rv = UA_ByteString_allocBuffer(&dst->securityHeader.messageNonce, - dst->securityHeader.nonceLength); - if(rv != UA_STATUSCODE_GOOD) - return rv; + // NonceLength + UA_Byte nonceLength; + rv = UA_Byte_decodeBinary(src, offset, &nonceLength); + UA_CHECK_STATUS(rv, return rv); - for (UA_Byte i = 0; i < dst->securityHeader.nonceLength; i++) { - rv = UA_Byte_decodeBinary(src, offset, &(dst->securityHeader.messageNonce.data[i])); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } + // MessageNonce + if(nonceLength > 0) { + //TODO: check for memory leaks + rv = UA_ByteString_allocBuffer(&dst->securityHeader.messageNonce, nonceLength); + UA_CHECK_STATUS(rv, return rv); + for (UA_Byte i = 0; i < nonceLength; i++) { + rv = UA_Byte_decodeBinary(src, offset, + &dst->securityHeader.messageNonce.data[i]); + UA_CHECK_STATUS(rv, return rv); } + } + // SecurityFooterSize + if(dst->securityHeader.securityFooterEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->securityHeader.securityFooterSize); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} - // SecurityFooterSize - if(dst->securityHeader.securityFooterEnabled) { - rv = UA_UInt16_decodeBinary(src, offset, &dst->securityHeader.securityFooterSize); - if(rv != UA_STATUSCODE_GOOD) - return rv; - } +UA_StatusCode +UA_NetworkMessage_decodeHeaders(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + + UA_StatusCode rv = UA_NetworkMessageHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + if (dst->groupHeaderEnabled) { + rv = UA_GroupHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + } + + if (dst->payloadHeaderEnabled) { + rv = UA_PayloadHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + } + + if (dst->securityEnabled) { + rv = UA_SecurityHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); } + rv = UA_ExtendedNetworkMessageHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_decodePayload(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + // Payload if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET) return UA_STATUSCODE_BADNOTIMPLEMENTED; + UA_StatusCode rv; + UA_Byte count = 1; if(dst->payloadHeaderEnabled) { count = dst->payloadHeader.dataSetPayloadHeader.count; @@ -27282,64 +26953,100 @@ UA_NetworkMessage_decodeBinaryInternal(const UA_ByteString *src, size_t *offset, dst->payload.dataSetPayload.sizes = (UA_UInt16 *)UA_Array_new(count, &UA_TYPES[UA_TYPES_UINT16]); for (UA_Byte i = 0; i < count; i++) { rv = UA_UInt16_decodeBinary(src, offset, &(dst->payload.dataSetPayload.sizes[i])); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } } dst->payload.dataSetPayload.dataSetMessages = (UA_DataSetMessage*) UA_calloc(count, sizeof(UA_DataSetMessage)); - for(UA_Byte i = 0; i < count; i++) { - rv = UA_DataSetMessage_decodeBinary(src, offset, &(dst->payload.dataSetPayload.dataSetMessages[i])); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_MEM(dst->payload.dataSetPayload.dataSetMessages, + return UA_STATUSCODE_BADOUTOFMEMORY); + + if(count == 1) + rv = UA_DataSetMessage_decodeBinary(src, offset, + &(dst->payload.dataSetPayload.dataSetMessages[0]), + 0); + else { + for(UA_Byte i = 0; i < count; i++) { + rv = UA_DataSetMessage_decodeBinary(src, offset, + &(dst->payload.dataSetPayload.dataSetMessages[i]), + dst->payload.dataSetPayload.sizes[i]); + } } + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; + + /** + * TODO: check if making the cleanup to free its own allocated memory is better, + * currently the free happens in a parent context + */ + // error: + // if (dst->payload.dataSetPayload.dataSetMessages) { + // UA_free(dst->payload.dataSetPayload.dataSetMessages); + // } + // return rv; +} - if(rv != UA_STATUSCODE_GOOD) - return rv; +UA_StatusCode +UA_NetworkMessage_decodeFooters(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { - if(dst->securityEnabled) { + if (dst->securityEnabled) { // SecurityFooter - if(dst->securityHeader.securityFooterEnabled && (dst->securityHeader.securityFooterSize > 0)) { - rv = UA_ByteString_allocBuffer(&dst->securityFooter, dst->securityHeader.securityFooterSize); - if (rv != UA_STATUSCODE_GOOD) - return rv; + if(dst->securityHeader.securityFooterEnabled && + (dst->securityHeader.securityFooterSize > 0)) { + UA_StatusCode rv = UA_ByteString_allocBuffer(&dst->securityFooter, + dst->securityHeader.securityFooterSize); + UA_CHECK_STATUS(rv, return rv); - for (UA_Byte i = 0; i < dst->securityHeader.securityFooterSize; i++) { + for(UA_UInt16 i = 0; i < dst->securityHeader.securityFooterSize; i++) { rv = UA_Byte_decodeBinary(src, offset, &(dst->securityFooter.data[i])); - if (rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } - - // Signature - if(dst->securityHeader.networkMessageSigned) { - rv = UA_ByteString_decodeBinary(src, offset, &(dst->signature)); - if (rv != UA_STATUSCODE_GOOD) - return rv; - } } - return UA_STATUSCODE_GOOD; } UA_StatusCode -UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkMessage* dst) { - UA_StatusCode retval = UA_NetworkMessage_decodeBinaryInternal(src, offset, dst); +UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { - if(retval != UA_STATUSCODE_GOOD) - UA_NetworkMessage_deleteMembers(dst); + UA_StatusCode rv = UA_STATUSCODE_GOOD; - return retval; + /* headers only need to be decoded when not in encryption mode + * because headers are already decoded when encryption mode is enabled + * to check for security parameters and decrypt/verify + * + * TODO: check if there is a workaround to use this function + * also when encryption is enabled + */ + // #ifndef UA_ENABLE_PUBSUB_ENCRYPTION + // if (*offset == 0) { + // rv = UA_NetworkMessage_decodeHeaders(src, offset, dst); + // UA_CHECK_STATUS(rv, return rv); + // } + // #endif + + rv = UA_NetworkMessage_decodeHeaders(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_decodePayload(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_decodeFooters(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; } static UA_Boolean increaseOffsetArray(UA_NetworkMessageOffsetBuffer *offsetBuffer) { UA_NetworkMessageOffset *tmpOffsets = (UA_NetworkMessageOffset *) UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffset) * (offsetBuffer->offsetsSize + (size_t)1)); - if(!tmpOffsets) - return false; + UA_CHECK_MEM(tmpOffsets, return false); + offsetBuffer->offsets = tmpOffsets; offsetBuffer->offsetsSize++; return true; @@ -27348,7 +27055,7 @@ increaseOffsetArray(UA_NetworkMessageOffsetBuffer *offsetBuffer) { size_t UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer) { size_t retval = 0; - UA_Byte byte; + UA_Byte byte = 0; size_t size = UA_Byte_calcSizeBinary(&byte); // UADPVersion + UADPFlags if(UA_NetworkMessage_ExtendedFlags1Enabled(p)) { size += UA_Byte_calcSizeBinary(&byte); @@ -27357,6 +27064,14 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu } if(p->publisherIdEnabled) { + if(offsetBuffer && offsetBuffer->RTsubscriberEnabled){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PUBLISHERID; + } switch (p->publisherIdType) { case UA_PUBLISHERDATATYPE_BYTE: size += UA_Byte_calcSizeBinary(&p->publisherId.publisherIdByte); @@ -27387,8 +27102,17 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu if(p->groupHeaderEnabled) { size += UA_Byte_calcSizeBinary(&byte); - if(p->groupHeader.writerGroupIdEnabled) + if(p->groupHeader.writerGroupIdEnabled) { + if(offsetBuffer && offsetBuffer->RTsubscriberEnabled){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_WRITERGROUPID; + } size += UA_UInt16_calcSizeBinary(&p->groupHeader.writerGroupId); + } if(p->groupHeader.groupVersionEnabled) size += UA_UInt32_calcSizeBinary(&p->groupHeader.groupVersion); @@ -27405,7 +27129,7 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu offsetBuffer->offsets[pos].offset = size; offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); UA_DataValue_init(offsetBuffer->offsets[pos].offsetData.value.value); - UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + UA_Variant_setScalarCopy(&offsetBuffer->offsets[pos].offsetData.value.value->value, &p->groupHeader.sequenceNumber, &UA_TYPES[UA_TYPES_UINT16]); offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER; } @@ -27418,6 +27142,13 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) { size += UA_Byte_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.count); if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != NULL) { + if(offsetBuffer && offsetBuffer->RTsubscriberEnabled){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_DATASETWRITERID; + } size += UA_UInt16_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]) * p->payloadHeader.dataSetPayloadHeader.count; } else { @@ -27459,9 +27190,8 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu if(p->securityEnabled) { size += UA_Byte_calcSizeBinary(&byte); size += UA_UInt32_calcSizeBinary(&p->securityHeader.securityTokenId); - size += UA_Byte_calcSizeBinary(&p->securityHeader.nonceLength); - if(p->securityHeader.nonceLength > 0) - size += (UA_Byte_calcSizeBinary(&p->securityHeader.messageNonce.data[0]) * p->securityHeader.nonceLength); + size += 1; /* UA_Byte_calcSizeBinary(&p->securityHeader.nonceLength); */ + size += p->securityHeader.messageNonce.length; if(p->securityHeader.securityFooterEnabled) size += UA_UInt16_calcSizeBinary(&p->securityHeader.securityFooterSize); } @@ -27482,12 +27212,9 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu } } - if (p->securityEnabled) { - if (p->securityHeader.securityFooterEnabled) + if(p->securityEnabled) { + if(p->securityHeader.securityFooterEnabled) size += p->securityHeader.securityFooterSize; - - if (p->securityHeader.networkMessageSigned) - size += UA_ByteString_calcSizeBinary(&p->signature); } retval = size; @@ -27495,12 +27222,11 @@ UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBu } void -UA_NetworkMessage_deleteMembers(UA_NetworkMessage* p) { +UA_NetworkMessage_clear(UA_NetworkMessage* p) { if(p->promotedFieldsEnabled) UA_Array_delete(p->promotedFields, p->promotedFieldsSize, &UA_TYPES[UA_TYPES_VARIANT]); - if(p->securityEnabled && (p->securityHeader.nonceLength > 0)) - UA_ByteString_deleteMembers(&p->securityHeader.messageNonce); + UA_ByteString_clear(&p->securityHeader.messageNonce); if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) { if(p->payloadHeaderEnabled) { @@ -27508,41 +27234,40 @@ UA_NetworkMessage_deleteMembers(UA_NetworkMessage* p) { UA_Array_delete(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds, p->payloadHeader.dataSetPayloadHeader.count, &UA_TYPES[UA_TYPES_UINT16]); } - if(p->payload.dataSetPayload.sizes != NULL) { UA_Array_delete(p->payload.dataSetPayload.sizes, p->payloadHeader.dataSetPayloadHeader.count, &UA_TYPES[UA_TYPES_UINT16]); } } - if(p->payload.dataSetPayload.dataSetMessages != NULL) { + if(p->payload.dataSetPayload.dataSetMessages) { UA_Byte count = 1; if(p->payloadHeaderEnabled) count = p->payloadHeader.dataSetPayloadHeader.count; - for (size_t i = 0; i < count; i++) - UA_DataSetMessage_free(&(p->payload.dataSetPayload.dataSetMessages[i])); + for(size_t i = 0; i < count; i++) + UA_DataSetMessage_clear(&(p->payload.dataSetPayload.dataSetMessages[i])); UA_free(p->payload.dataSetPayload.dataSetMessages); } } if(p->securityHeader.securityFooterEnabled && (p->securityHeader.securityFooterSize > 0)) - UA_ByteString_deleteMembers(&p->securityFooter); + UA_ByteString_clear(&p->securityFooter); if(p->messageIdEnabled){ - UA_String_deleteMembers(&p->messageId); + UA_String_clear(&p->messageId); } if(p->publisherIdEnabled && p->publisherIdType == UA_PUBLISHERDATATYPE_STRING){ - UA_String_deleteMembers(&p->publisherId.publisherIdString); + UA_String_clear(&p->publisherId.publisherIdString); } memset(p, 0, sizeof(UA_NetworkMessage)); } void UA_NetworkMessage_delete(UA_NetworkMessage* p) { - UA_NetworkMessage_deleteMembers(p); + UA_NetworkMessage_clear(p); } UA_Boolean @@ -27606,9 +27331,8 @@ UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, UA_Byte v |= DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK; UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - + UA_CHECK_STATUS(rv, return rv); + // DataSetFlags2 if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src)) { v = (UA_Byte)src->dataSetMessageType; @@ -27620,63 +27344,96 @@ UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, UA_Byte v |= DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK; rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // DataSetMessageSequenceNr if(src->dataSetMessageSequenceNrEnabled) { rv = UA_UInt16_encodeBinary(&src->dataSetMessageSequenceNr, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // Timestamp if(src->timestampEnabled) { rv = UA_DateTime_encodeBinary(&(src->timestamp), bufPos, bufEnd); /* UtcTime */ - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // PicoSeconds if(src->picoSecondsIncluded) { rv = UA_UInt16_encodeBinary(&(src->picoSeconds), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // Status if(src->statusEnabled) { rv = UA_UInt16_encodeBinary(&(src->status), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // ConfigVersionMajorVersion if(src->configVersionMajorVersionEnabled) { rv = UA_UInt32_encodeBinary(&(src->configVersionMajorVersion), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } // ConfigVersionMinorVersion if(src->configVersionMinorVersionEnabled) { rv = UA_UInt32_encodeBinary(&(src->configVersionMinorVersion), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } return UA_STATUSCODE_GOOD; } +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + +UA_StatusCode +UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode, + UA_PubSubSecurityPolicy *policy, void *policyContext, + UA_Byte *messageStart, UA_Byte *encryptStart, + UA_Byte *sigStart) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + + /* Encrypt the payload */ + if(securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + /* Set the temporary MessageNonce in the SecurityPolicy */ + res = policy->setMessageNonce(policyContext, &nm->securityHeader.messageNonce); + UA_CHECK_STATUS(res, return res); + + /* The encryption is done in-place, no need to encode again */ + UA_ByteString encryptBuf; + encryptBuf.data = encryptStart; + encryptBuf.length = (uintptr_t)sigStart - (uintptr_t)encryptStart; + res = policy->symmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(policyContext, &encryptBuf); + UA_CHECK_STATUS(res, return res); + } + + /* Sign the entire message */ + if(securityMode == UA_MESSAGESECURITYMODE_SIGN || + securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + UA_ByteString sigBuf; + sigBuf.length = (uintptr_t)sigStart - (uintptr_t)messageStart; + sigBuf.data = messageStart; + size_t sigSize = policy->symmetricModule.cryptoModule. + signatureAlgorithm.getLocalSignatureSize(policyContext); + UA_ByteString sig = {sigSize, sigStart}; + res = policy->symmetricModule.cryptoModule. + signatureAlgorithm.sign(policyContext, &sigBuf, &sig); + } + + return res; +} +#endif + UA_StatusCode UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataSetMessageHeader* dst) { memset(dst, 0, sizeof(UA_DataSetMessageHeader)); UA_Byte v = 0; UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); UA_Byte v2 = v & DS_MESSAGEHEADER_FIELD_ENCODING_MASK; v2 = (UA_Byte)(v2 >> DS_MH_SHIFT_LEN); @@ -27700,9 +27457,8 @@ UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, if((v & DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK) != 0) { v = 0; rv = UA_Byte_decodeBinary(src, offset, &v); - if(rv != UA_STATUSCODE_GOOD) - return rv; - + UA_CHECK_STATUS(rv, return rv); + dst->dataSetMessageType = (UA_DataSetMessageType)(v & DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK); if((v & DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK) != 0) @@ -27717,48 +27473,42 @@ UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, if(dst->dataSetMessageSequenceNrEnabled) { rv = UA_UInt16_decodeBinary(src, offset, &dst->dataSetMessageSequenceNr); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } else { dst->dataSetMessageSequenceNr = 0; } if(dst->timestampEnabled) { rv = UA_DateTime_decodeBinary(src, offset, &dst->timestamp); /* UtcTime */ - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } else { dst->timestamp = 0; } if(dst->picoSecondsIncluded) { rv = UA_UInt16_decodeBinary(src, offset, &dst->picoSeconds); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } else { dst->picoSeconds = 0; } if(dst->statusEnabled) { rv = UA_UInt16_decodeBinary(src, offset, &dst->status); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } else { dst->status = 0; } if(dst->configVersionMajorVersionEnabled) { rv = UA_UInt32_decodeBinary(src, offset, &dst->configVersionMajorVersion); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } else { dst->configVersionMajorVersion = 0; } if(dst->configVersionMinorVersionEnabled) { rv = UA_UInt32_decodeBinary(src, offset, &dst->configVersionMinorVersion); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } else { dst->configVersionMinorVersion = 0; } @@ -27768,7 +27518,7 @@ UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, size_t UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p) { - UA_Byte byte; + UA_Byte byte = 0; size_t size = UA_Byte_calcSizeBinary(&byte); // DataSetMessage Type + Flags if(UA_DataSetMessageHeader_DataSetFlags2Enabled(p)) size += UA_Byte_calcSizeBinary(&byte); @@ -27798,59 +27548,54 @@ UA_StatusCode UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos, const UA_Byte *bufEnd) { UA_StatusCode rv = UA_DataSetMessageHeader_encodeBinary(&src->header, bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { if(src->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) { rv = UA_UInt16_encodeBinary(&(src->data.keyFrameData.fieldCount), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } - if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) { rv = UA_Variant_encodeBinary(&(src->data.keyFrameData.dataSetFields[i].value), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { - return UA_STATUSCODE_BADNOTIMPLEMENTED; + for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) { + rv = UA_encodeBinaryInternal(src->data.keyFrameData.dataSetFields[i].value.data, + src->data.keyFrameData.dataSetFields[i].value.type, + bufPos, &bufEnd, NULL, NULL); + UA_CHECK_STATUS(rv, return rv); + } } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) { rv = UA_DataValue_encodeBinary(&(src->data.keyFrameData.dataSetFields[i]), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } } else if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { // Encode Delta Frame // Here the FieldCount is always present rv = UA_UInt16_encodeBinary(&(src->data.keyFrameData.fieldCount), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) { rv = UA_UInt16_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldIndex), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; - + UA_CHECK_STATUS(rv, return rv); + rv = UA_Variant_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue.value), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { return UA_STATUSCODE_BADNOTIMPLEMENTED; } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) { rv = UA_UInt16_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldIndex), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); rv = UA_DataValue_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue), bufPos, bufEnd); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } } } else if(src->header.dataSetMessageType != UA_DATASETMESSAGE_KEEPALIVE) { @@ -27862,76 +27607,97 @@ UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos, } UA_StatusCode -UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataSetMessage* dst) { +UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataSetMessage* dst, UA_UInt16 dsmSize) { + size_t initialOffset = *offset; memset(dst, 0, sizeof(UA_DataSetMessage)); UA_StatusCode rv = UA_DataSetMessageHeader_decodeBinary(src, offset, &dst->header); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); if(dst->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { - if(dst->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) { - rv = UA_UInt16_decodeBinary(src, offset, &dst->data.keyFrameData.fieldCount); - if(rv != UA_STATUSCODE_GOOD) - return rv; - - if(dst->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + switch(dst->header.fieldEncoding) { + case UA_FIELDENCODING_VARIANT: + { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.keyFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); dst->data.keyFrameData.dataSetFields = (UA_DataValue *)UA_Array_new(dst->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]); for (UA_UInt16 i = 0; i < dst->data.keyFrameData.fieldCount; i++) { UA_DataValue_init(&dst->data.keyFrameData.dataSetFields[i]); rv = UA_Variant_decodeBinary(src, offset, &dst->data.keyFrameData.dataSetFields[i].value); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); + dst->data.keyFrameData.dataSetFields[i].hasValue = true; } - } else if(dst->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { - return UA_STATUSCODE_BADNOTIMPLEMENTED; - } else if(dst->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + break; + } + case UA_FIELDENCODING_DATAVALUE: + { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.keyFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); dst->data.keyFrameData.dataSetFields = (UA_DataValue *)UA_Array_new(dst->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]); for (UA_UInt16 i = 0; i < dst->data.keyFrameData.fieldCount; i++) { rv = UA_DataValue_decodeBinary(src, offset, &(dst->data.keyFrameData.dataSetFields[i])); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } + break; } + case UA_FIELDENCODING_RAWDATA: + { + dst->data.keyFrameData.rawFields.data = &src->data[*offset]; + dst->data.keyFrameData.rawFields.length = dsmSize; + if(dsmSize == 0){ + //TODO calculate the length of the DSM-Payload for a single DSM + //Problem: Size is not set and MetaData information are needed. + //Increase offset to avoid endless chunk loop. Needs to be fixed when + //pubsub security footer and signatur is enabled. + *offset += 1500; + } else { + *offset += (dsmSize - (*offset - initialOffset)); + } + break; + } + default: + return UA_STATUSCODE_BADINTERNALERROR; } } else if(dst->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { - if(dst->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) { - rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.fieldCount); - if(rv != UA_STATUSCODE_GOOD) - return rv; - - if(dst->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + switch(dst->header.fieldEncoding) { + case UA_FIELDENCODING_VARIANT: { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); size_t memsize = sizeof(UA_DataSetMessage_DeltaFrameField) * dst->data.deltaFrameData.fieldCount; dst->data.deltaFrameData.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)UA_malloc(memsize); for (UA_UInt16 i = 0; i < dst->data.deltaFrameData.fieldCount; i++) { rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.deltaFrameFields[i].fieldIndex); - if(rv != UA_STATUSCODE_GOOD) - return rv; - + UA_CHECK_STATUS(rv, return rv); + UA_DataValue_init(&dst->data.deltaFrameData.deltaFrameFields[i].fieldValue); rv = UA_Variant_decodeBinary(src, offset, &dst->data.deltaFrameData.deltaFrameFields[i].fieldValue.value); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); dst->data.deltaFrameData.deltaFrameFields[i].fieldValue.hasValue = true; } - } else if(dst->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { - return UA_STATUSCODE_BADNOTIMPLEMENTED; - } else if(dst->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + break; + } + case UA_FIELDENCODING_DATAVALUE: { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); size_t memsize = sizeof(UA_DataSetMessage_DeltaFrameField) * dst->data.deltaFrameData.fieldCount; dst->data.deltaFrameData.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)UA_malloc(memsize); for (UA_UInt16 i = 0; i < dst->data.deltaFrameData.fieldCount; i++) { rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.deltaFrameFields[i].fieldIndex); - if(rv != UA_STATUSCODE_GOOD) - return rv; - + UA_CHECK_STATUS(rv, return rv); + rv = UA_DataValue_decodeBinary(src, offset, &(dst->data.deltaFrameData.deltaFrameFields[i].fieldValue)); - if(rv != UA_STATUSCODE_GOOD) - return rv; + UA_CHECK_STATUS(rv, return rv); } + break; } + case UA_FIELDENCODING_RAWDATA: { + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + default: + return UA_STATUSCODE_BADINTERNALERROR; } } else if(dst->header.dataSetMessageType != UA_DATASETMESSAGE_KEEPALIVE) { return UA_STATUSCODE_BADNOTIMPLEMENTED; @@ -27944,7 +27710,20 @@ UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Data size_t UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBuffer *offsetBuffer, size_t currentOffset) { size_t size = currentOffset; - UA_Byte byte; + + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + UA_DataValue_init(offsetBuffer->offsets[pos].offsetData.value.value); + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + &p->header.fieldEncoding, &UA_TYPES[UA_TYPES_UINT32]); + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING; + } + + UA_Byte byte = 0; size += UA_Byte_calcSizeBinary(&byte); // DataSetMessage Type + Flags if(UA_DataSetMessageHeader_DataSetFlags2Enabled(&p->header)) size += UA_Byte_calcSizeBinary(&byte); @@ -27957,7 +27736,7 @@ UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBu offsetBuffer->offsets[pos].offset = size; offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); UA_DataValue_init(offsetBuffer->offsets[pos].offsetData.value.value); - UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + UA_Variant_setScalarCopy(&offsetBuffer->offsets[pos].offsetData.value.value->value, &p->header.dataSetMessageSequenceNr, &UA_TYPES[UA_TYPES_UINT16]); offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER; } @@ -27981,10 +27760,8 @@ UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBu if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA){ - //TODO clarify RT and Rawdata behavior size += UA_calcSizeBinary(&p->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]); } - if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){ if (offsetBuffer) { @@ -27994,16 +27771,35 @@ UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBu offsetBuffer->offsets[pos].offset = size; offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT; //TODO check value source and alloc! + //offsetBuffer->offsets[pos].offsetData.value.value = p->data.keyFrameData.dataSetFields; offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, p->data.keyFrameData.dataSetFields[i].value.data, p->data.keyFrameData.dataSetFields[i].value.type); - //offsetBuffer->offsets[pos].offsetData.value.value->value = p->data.keyFrameData.dataSetFields->value; + offsetBuffer->offsets[pos].offsetData.value.value->value.storageType = UA_VARIANT_DATA_NODELETE; } size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i].value, &UA_TYPES[UA_TYPES_VARIANT]); } } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { - // not implemented + for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){ + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + //init offset buffer with the latest value + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + p->data.keyFrameData.dataSetFields[i].value.data, + p->data.keyFrameData.dataSetFields[i].value.type); + offsetBuffer->offsets[pos].offsetData.value.value->value.storageType = UA_VARIANT_DATA_NODELETE; + //count the memory size of the specific field + offsetBuffer->rawMessageLength += p->data.keyFrameData.dataSetFields[i].value.type->memSize; + } + size += UA_calcSizeBinary(p->data.keyFrameData.dataSetFields[i].value.data, + p->data.keyFrameData.dataSetFields[i].value.type); + } } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++) { if (offsetBuffer) { @@ -28041,23 +27837,28 @@ UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBu return size; } -void UA_DataSetMessage_free(const UA_DataSetMessage* p) { +void +UA_DataSetMessage_clear(const UA_DataSetMessage* p) { if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { - if(p->data.keyFrameData.dataSetFields != NULL) - UA_Array_delete(p->data.keyFrameData.dataSetFields, p->data.keyFrameData.fieldCount, + if(p->data.keyFrameData.dataSetFields != NULL) { + UA_Array_delete(p->data.keyFrameData.dataSetFields, + p->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]); + } + /* Json keys */ if(p->data.keyFrameData.fieldNames != NULL){ - UA_Array_delete(p->data.keyFrameData.fieldNames, p->data.keyFrameData.fieldCount, + UA_Array_delete(p->data.keyFrameData.fieldNames, + p->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_STRING]); } } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { if(p->data.deltaFrameData.deltaFrameFields != NULL) { for(UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) { if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { - UA_DataValue_deleteMembers(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue); + UA_DataValue_clear(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue); } else if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { - UA_Variant_deleteMembers(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue.value); + UA_Variant_clear(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue.value); } } UA_free(p->data.deltaFrameData.deltaFrameFields); @@ -28066,7 +27867,7 @@ void UA_DataSetMessage_free(const UA_DataSetMessage* p) { } #endif /* UA_ENABLE_PUBSUB */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_writer.c" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_writer.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -28074,7 +27875,10 @@ void UA_DataSetMessage_free(const UA_DataSetMessage* p) { * * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner) * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2019-2021 Kalycito Infotech Private Limited + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes) */ @@ -28087,22 +27891,9 @@ void UA_DataSetMessage_free(const UA_DataSetMessage* p) { #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES #endif -#define UA_MAX_STACKBUF 512 /* Max size of network messages on the stack */ - /* Forward declaration */ static void -UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup); -static void UA_DataSetField_clear(UA_DataSetField *field); -static UA_StatusCode -generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg, - UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount, - UA_ExtensionObject *messageSettings, - UA_ExtensionObject *transportSettings, - UA_NetworkMessage *networkMessage); -static UA_StatusCode -UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage, - UA_DataSetWriter *dataSetWriter); /**********************************************/ /* Connection */ @@ -28116,7 +27907,8 @@ UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src, res |= UA_String_copy(&src->name, &dst->name); res |= UA_Variant_copy(&src->address, &dst->address); res |= UA_String_copy(&src->transportProfileUri, &dst->transportProfileUri); - res |= UA_Variant_copy(&src->connectionTransportSettings, &dst->connectionTransportSettings); + res |= UA_Variant_copy(&src->connectionTransportSettings, + &dst->connectionTransportSettings); if(src->connectionPropertiesSize > 0) { dst->connectionProperties = (UA_KeyValuePair *) UA_calloc(src->connectionPropertiesSize, sizeof(UA_KeyValuePair)); @@ -28141,12 +27933,10 @@ UA_Server_getPubSubConnectionConfig(UA_Server *server, const UA_NodeId connectio UA_PubSubConnectionConfig *config) { if(!config) return UA_STATUSCODE_BADINVALIDARGUMENT; - UA_PubSubConnection *currentPubSubConnection = UA_PubSubConnection_findConnectionbyId(server, connection); if(!currentPubSubConnection) return UA_STATUSCODE_BADNOTFOUND; - return UA_PubSubConnectionConfig_copy(currentPubSubConnection->config, config); } @@ -28193,306 +27983,23 @@ UA_PubSubConnection_clear(UA_Server *server, UA_PubSubConnection *connection) { UA_free(connection->config); } -UA_StatusCode -UA_PubSubConnection_regist(UA_Server *server, UA_NodeId *connectionIdentifier) { - UA_PubSubConnection *connection = - UA_PubSubConnection_findConnectionbyId(server, *connectionIdentifier); - if(!connection) - return UA_STATUSCODE_BADNOTFOUND; - - UA_StatusCode retval = connection->channel->regist(connection->channel, NULL, NULL); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "register channel failed: 0x%" PRIx32 "!", retval); - } - return retval; -} - -UA_StatusCode -UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection, - const UA_WriterGroupConfig *writerGroupConfig, - UA_NodeId *writerGroupIdentifier) { - if(!writerGroupConfig) - return UA_STATUSCODE_BADINVALIDARGUMENT; - //search the connection by the given connectionIdentifier - UA_PubSubConnection *currentConnectionContext = - UA_PubSubConnection_findConnectionbyId(server, connection); - if(!currentConnectionContext) - return UA_STATUSCODE_BADNOTFOUND; - - if(currentConnectionContext->config->configurationFrozen){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Adding WriterGroup failed. PubSubConnection is frozen."); - return UA_STATUSCODE_BADCONFIGURATIONERROR; - } - - /* Validate messageSettings type */ - if (writerGroupConfig->messageSettings.content.decoded.type) { - if (writerGroupConfig->encodingMimeType == UA_PUBSUB_ENCODING_JSON && - (writerGroupConfig->messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED - || writerGroupConfig->messageSettings.content.decoded.type->typeIndex != UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE) ) { - return UA_STATUSCODE_BADTYPEMISMATCH; - } - - if (writerGroupConfig->encodingMimeType == UA_PUBSUB_ENCODING_UADP && - (writerGroupConfig->messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED - || writerGroupConfig->messageSettings.content.decoded.type->typeIndex != UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE) ) { - return UA_STATUSCODE_BADTYPEMISMATCH; - } - } - - - //allocate memory for new WriterGroup - UA_WriterGroup *newWriterGroup = (UA_WriterGroup *) UA_calloc(1, sizeof(UA_WriterGroup)); - if(!newWriterGroup) - return UA_STATUSCODE_BADOUTOFMEMORY; - - newWriterGroup->linkedConnection = currentConnectionContext; - UA_PubSubManager_generateUniqueNodeId(server, &newWriterGroup->identifier); - if(writerGroupIdentifier) - UA_NodeId_copy(&newWriterGroup->identifier, writerGroupIdentifier); - - //deep copy of the config - UA_WriterGroupConfig tmpWriterGroupConfig; - UA_StatusCode retVal = UA_WriterGroupConfig_copy(writerGroupConfig, &tmpWriterGroupConfig); - - if(!tmpWriterGroupConfig.messageSettings.content.decoded.type) { - UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new(); - tmpWriterGroupConfig.messageSettings.content.decoded.data = wgm; - tmpWriterGroupConfig.messageSettings.content.decoded.type = - &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]; - tmpWriterGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED; - } - newWriterGroup->config = tmpWriterGroupConfig; - LIST_INSERT_HEAD(¤tConnectionContext->writerGroups, newWriterGroup, listEntry); -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - addWriterGroupRepresentation(server, newWriterGroup); -#endif - return retVal; -} - -UA_StatusCode -UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup) { - UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); - if(!wg) - return UA_STATUSCODE_BADNOTFOUND; - - if(wg->config.configurationFrozen){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Delete WriterGroup failed. WriterGroup is frozen."); - return UA_STATUSCODE_BADCONFIGURATIONERROR; - } - - UA_PubSubConnection *connection = wg->linkedConnection; - if(!connection) - return UA_STATUSCODE_BADNOTFOUND; - - if(connection->config->configurationFrozen){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Delete WriterGroup failed. PubSubConnection is frozen."); - return UA_STATUSCODE_BADCONFIGURATIONERROR; - } - if(wg->state == UA_PUBSUBSTATE_OPERATIONAL){ - //unregister the publish callback - UA_PubSubManager_removeRepeatedPubSubCallback(server, wg->publishCallbackId); - } -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - removeGroupRepresentation(server, wg); -#endif - - UA_WriterGroup_clear(server, wg); - LIST_REMOVE(wg, listEntry); - UA_free(wg); - return UA_STATUSCODE_GOOD; -} - -UA_StatusCode -UA_Server_freezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup) { - UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); - if(!wg) - return UA_STATUSCODE_BADNOTFOUND; - - //PubSubConnection freezeCounter++ - UA_PubSubConnection *pubSubConnection = wg->linkedConnection; - pubSubConnection->configurationFreezeCounter++; - pubSubConnection->config->configurationFrozen = UA_TRUE; - //WriterGroup freeze - wg->config.configurationFrozen = UA_TRUE; - //DataSetWriter freeze - UA_DataSetWriter *dataSetWriter; - LIST_FOREACH(dataSetWriter, &wg->writers, listEntry){ - dataSetWriter->config.configurationFrozen = UA_TRUE; - //PublishedDataSet freezeCounter++ - UA_PublishedDataSet *publishedDataSet = - UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet); - publishedDataSet->configurationFreezeCounter++; - publishedDataSet->config.configurationFrozen = UA_TRUE; - //DataSetFields freeze - UA_DataSetField *dataSetField; - TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){ - dataSetField->config.configurationFrozen = UA_TRUE; - } - } - - if(wg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE){ - size_t dsmCount = 0; - if(wg->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub-RT configuration fail: Non-RT capable encoding."); - return UA_STATUSCODE_BADNOTSUPPORTED; - } - //TODO Clarify: should we only allow = maxEncapsulatedDataSetMessageCount == 1 with RT? - //TODO Clarify: Behaviour if the finale size is more than MTU - /* Generate data set messages */ - UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount); - UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount); - UA_DataSetWriter *dsw; - LIST_FOREACH(dsw, &wg->writers, listEntry) { - /* Find the dataset */ - UA_PublishedDataSet *pds = - UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet); - if(!pds) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub Publish: PublishedDataSet not found"); - continue; - } - if(pds->promotedFieldsCount > 0) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub-RT configuration fail: PDS contains promoted fields."); - return UA_STATUSCODE_BADNOTSUPPORTED; - } - UA_DataSetField *dsf; - TAILQ_FOREACH(dsf, &pds->fields, listEntry){ - if(!dsf->config.field.variable.staticValueSourceEnabled){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub-RT configuration fail: PDS contains variables with dynamic length types."); - return UA_STATUSCODE_BADNOTSUPPORTED; - } - if((UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_STRING].typeId) || - UA_NodeId_equal(&dsf->fieldMetaData.dataType, - &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) && - dsf->fieldMetaData.maxStringLength == 0) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub-RT configuration fail: " - "PDS contains String/ByteString with dynamic length."); - return UA_STATUSCODE_BADNOTSUPPORTED; - } else if(!UA_DataType_isNumeric(UA_findDataType(&dsf->fieldMetaData.dataType))){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub-RT configuration fail: " - "PDS contains variable with dynamic size."); - return UA_STATUSCODE_BADNOTSUPPORTED; - } - } - /* Generate the DSM */ - UA_StatusCode res = - UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw); - if(res != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub RT Offset calculation: DataSetMessage buffering failed"); - continue; - } - dsWriterIds[dsmCount] = dsw->config.dataSetWriterId; - dsmCount++; - } - UA_NetworkMessage networkMessage; - memset(&networkMessage, 0, sizeof(networkMessage)); - UA_StatusCode res = - generateNetworkMessage(pubSubConnection, wg, dsmStore, dsWriterIds, (UA_Byte) dsmCount, - &wg->config.messageSettings, &wg->config.transportSettings, - &networkMessage); - if(res != UA_STATUSCODE_GOOD) - return UA_STATUSCODE_BADINTERNALERROR; - UA_NetworkMessage_calcSizeBinary(&networkMessage, &wg->bufferedMessage); - /* Allocate the buffer. Allocate on the stack if the buffer is small. */ - UA_ByteString buf; - size_t msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage, NULL); - res = UA_ByteString_allocBuffer(&buf, msgSize); - if(res != UA_STATUSCODE_GOOD) - return UA_STATUSCODE_BADOUTOFMEMORY; - wg->bufferedMessage.buffer = buf; - const UA_Byte *bufEnd = &wg->bufferedMessage.buffer.data[wg->bufferedMessage.buffer.length]; - UA_Byte *bufPos = wg->bufferedMessage.buffer.data; - UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd); - /* Clean up DSM */ - for(size_t i = 0; i < dsmCount; i++){ - UA_free(dsmStore[i].data.keyFrameData.dataSetFields); -#ifdef UA_ENABLE_JSON_ENCODING - UA_free(dsmStore[i].data.keyFrameData.fieldNames); -#endif - } - } - return UA_STATUSCODE_GOOD; -} - -UA_StatusCode -UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, const UA_NodeId writerGroup){ - UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); - if(!wg) - return UA_STATUSCODE_BADNOTFOUND; - //if(wg->config.rtLevel == UA_PUBSUB_RT_NONE){ - // UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - // "PubSub configuration freeze without RT configuration has no effect."); - // return UA_STATUSCODE_BADCONFIGURATIONERROR; - //} - //PubSubConnection freezeCounter-- - UA_PubSubConnection *pubSubConnection = wg->linkedConnection; - pubSubConnection->configurationFreezeCounter--; - if(pubSubConnection->configurationFreezeCounter == 0){ - pubSubConnection->config->configurationFrozen = UA_FALSE; - } - //WriterGroup unfreeze - wg->config.configurationFrozen = UA_FALSE; - //DataSetWriter unfreeze - UA_DataSetWriter *dataSetWriter; - LIST_FOREACH(dataSetWriter, &wg->writers, listEntry) { - UA_PublishedDataSet *publishedDataSet = - UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet); - //PublishedDataSet freezeCounter-- - publishedDataSet->configurationFreezeCounter--; - if(publishedDataSet->configurationFreezeCounter == 0){ - publishedDataSet->config.configurationFrozen = UA_FALSE; - UA_DataSetField *dataSetField; - TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){ - dataSetField->config.configurationFrozen = UA_FALSE; - } - } - dataSetWriter->config.configurationFrozen = UA_FALSE; - } - return UA_STATUSCODE_GOOD; -} - -UA_StatusCode UA_EXPORT -UA_Server_setWriterGroupOperational(UA_Server *server, const UA_NodeId writerGroup){ - UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); - if(!wg) - return UA_STATUSCODE_BADNOTFOUND; - return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, wg); -} - -UA_StatusCode UA_EXPORT -UA_Server_setWriterGroupDisabled(UA_Server *server, const UA_NodeId writerGroup){ - UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); - if(!wg) - return UA_STATUSCODE_BADNOTFOUND; - return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, wg); -} - /**********************************************/ /* PublishedDataSet */ /**********************************************/ + UA_StatusCode UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src, UA_PublishedDataSetConfig *dst) { UA_StatusCode res = UA_STATUSCODE_GOOD; memcpy(dst, src, sizeof(UA_PublishedDataSetConfig)); res |= UA_String_copy(&src->name, &dst->name); - switch(src->publishedDataSetType){ + switch(src->publishedDataSetType) { case UA_PUBSUB_DATASET_PUBLISHEDITEMS: //no additional items break; case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE: - if(src->config.itemsTemplate.variablesToAddSize > 0){ + if(src->config.itemsTemplate.variablesToAddSize > 0) { dst->config.itemsTemplate.variablesToAdd = (UA_PublishedVariableDataType *) UA_calloc(src->config.itemsTemplate.variablesToAddSize, sizeof(UA_PublishedVariableDataType)); @@ -28504,7 +28011,7 @@ UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src, src->config.itemsTemplate.variablesToAddSize; } - for(size_t i = 0; i < src->config.itemsTemplate.variablesToAddSize; i++){ + for(size_t i = 0; i < src->config.itemsTemplate.variablesToAddSize; i++) { res |= UA_PublishedVariableDataType_copy(&src->config.itemsTemplate.variablesToAdd[i], &dst->config.itemsTemplate.variablesToAdd[i]); } @@ -28524,19 +28031,13 @@ UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src, UA_StatusCode UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds, - UA_PublishedDataSetConfig *config){ + UA_PublishedDataSetConfig *config) { if(!config) return UA_STATUSCODE_BADINVALIDARGUMENT; - - UA_PublishedDataSet *currentPublishedDataSet = UA_PublishedDataSet_findPDSbyId(server, pds); - if(!currentPublishedDataSet) + UA_PublishedDataSet *currentPDS = UA_PublishedDataSet_findPDSbyId(server, pds); + if(!currentPDS) return UA_STATUSCODE_BADNOTFOUND; - - UA_PublishedDataSetConfig tmpPublishedDataSetConfig; - //deep copy of the actual config - UA_PublishedDataSetConfig_copy(¤tPublishedDataSet->config, &tmpPublishedDataSetConfig); - *config = tmpPublishedDataSetConfig; - return UA_STATUSCODE_GOOD; + return UA_PublishedDataSetConfig_copy(¤tPDS->config, config); } UA_StatusCode @@ -28544,17 +28045,15 @@ UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds, UA_DataSetMetaDataType *metaData) { if(!metaData) return UA_STATUSCODE_BADINVALIDARGUMENT; - - UA_PublishedDataSet *currentPublishedDataSet = UA_PublishedDataSet_findPDSbyId(server, pds); - if(!currentPublishedDataSet) + UA_PublishedDataSet *currentPDS = UA_PublishedDataSet_findPDSbyId(server, pds); + if(!currentPDS) return UA_STATUSCODE_BADNOTFOUND; - - return UA_DataSetMetaDataType_copy(¤tPublishedDataSet->dataSetMetaData, metaData); + return UA_DataSetMetaDataType_copy(¤tPDS->dataSetMetaData, metaData); } UA_PublishedDataSet * UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier) { - UA_PublishedDataSet *tmpPDS; + UA_PublishedDataSet *tmpPDS = NULL; TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry) { if(UA_NodeId_equal(&tmpPDS->identifier, &identifier)) break; @@ -28586,259 +28085,312 @@ UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig) { void UA_PublishedDataSet_clear(UA_Server *server, UA_PublishedDataSet *publishedDataSet) { - UA_PublishedDataSetConfig_clear(&publishedDataSet->config); - //delete PDS UA_DataSetField *field, *tmpField; TAILQ_FOREACH_SAFE(field, &publishedDataSet->fields, listEntry, tmpField) { UA_Server_removeDataSetField(server, field->identifier); } + UA_PublishedDataSetConfig_clear(&publishedDataSet->config); UA_DataSetMetaDataType_clear(&publishedDataSet->dataSetMetaData); UA_NodeId_clear(&publishedDataSet->identifier); } +/* The fieldMetaData variable has to be cleaned up external in case of an error */ static UA_StatusCode -generateFieldMetaData(UA_Server *server, UA_DataSetField *field, UA_FieldMetaData *fieldMetaData) { - switch (field->config.dataSetFieldType){ - case UA_PUBSUB_DATASETFIELD_VARIABLE: - if(UA_String_copy(&field->config.field.variable.fieldNameAlias, &fieldMetaData->name) != UA_STATUSCODE_GOOD) - return UA_STATUSCODE_BADINTERNALERROR; - fieldMetaData->description = UA_LOCALIZEDTEXT_ALLOC("", ""); - fieldMetaData->dataSetFieldId = UA_GUID_NULL; - - //ToDo after freeze PR, the value source must be checked (other behavior for static value source) - if(field->config.field.variable.staticValueSourceEnabled) { - if (field->config.field.variable.staticValueSource.value.arrayDimensionsSize > 0) { - fieldMetaData->arrayDimensions = (UA_UInt32 *) UA_calloc( - field->config.field.variable.staticValueSource.value.arrayDimensionsSize, sizeof(UA_UInt32)); - if(fieldMetaData->arrayDimensions == NULL) - return UA_STATUSCODE_BADOUTOFMEMORY; - memcpy(fieldMetaData->arrayDimensions, - field->config.field.variable.staticValueSource.value.arrayDimensions, - sizeof(UA_UInt32) *field->config.field.variable.staticValueSource.value.arrayDimensionsSize); - } - fieldMetaData->arrayDimensionsSize = field->config.field.variable.staticValueSource.value.arrayDimensionsSize; - if(UA_NodeId_copy(&field->config.field.variable.staticValueSource.value.type->typeId, - &fieldMetaData->dataType) != UA_STATUSCODE_GOOD){ - if(fieldMetaData->arrayDimensions){ - UA_free(fieldMetaData->arrayDimensions); - return UA_STATUSCODE_BADINTERNALERROR; - } - } - fieldMetaData->properties = NULL; - fieldMetaData->propertiesSize = 0; - //TODO collect value rank for the static field source - fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE; - return UA_STATUSCODE_GOOD; - } - UA_Variant value; - UA_Variant_init(&value); - if(UA_Server_readArrayDimensions(server, field->config.field.variable.publishParameters.publishedVariable, - &value) != UA_STATUSCODE_GOOD){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub meta data generation. Reading ArrayDimension failed."); - } else { - if (value.arrayDimensionsSize > 0) { - fieldMetaData->arrayDimensions = (UA_UInt32 *) UA_calloc(value.arrayDimensionsSize, sizeof(UA_UInt32)); - if(fieldMetaData->arrayDimensions == NULL) - return UA_STATUSCODE_BADOUTOFMEMORY; - memcpy(fieldMetaData->arrayDimensions, value.arrayDimensions, sizeof(UA_UInt32)*value.arrayDimensionsSize); - } - fieldMetaData->arrayDimensionsSize = value.arrayDimensionsSize; - } - if(UA_Server_readDataType(server, field->config.field.variable.publishParameters.publishedVariable, - &fieldMetaData->dataType) != UA_STATUSCODE_GOOD){ - if(fieldMetaData->arrayDimensions){ - UA_free(fieldMetaData->arrayDimensions); - return UA_STATUSCODE_BADINTERNALERROR; - } - } - fieldMetaData->properties = NULL; - fieldMetaData->propertiesSize = 0; - UA_Int32 valueRank; - if(UA_Server_readValueRank(server, field->config.field.variable.publishParameters.publishedVariable, - &valueRank) != UA_STATUSCODE_GOOD){ - if(fieldMetaData->arrayDimensions){ - UA_free(fieldMetaData->arrayDimensions); - return UA_STATUSCODE_BADINTERNALERROR; - } - } - fieldMetaData->valueRank = valueRank; - if(field->config.field.variable.promotedField){ - fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_PROMOTEDFIELD; - } else { - fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE; - } - //TODO collect the following fields - //fieldMetaData.builtInType - //fieldMetaData.maxStringLength - return UA_STATUSCODE_GOOD; - case UA_PUBSUB_DATASETFIELD_EVENT: - return UA_STATUSCODE_BADNOTSUPPORTED; - default: - return UA_STATUSCODE_BADNOTSUPPORTED; +generateFieldMetaData(UA_Server *server, UA_DataSetField *field, + UA_FieldMetaData *fieldMetaData) { + if(field->config.dataSetFieldType != UA_PUBSUB_DATASETFIELD_VARIABLE) + return UA_STATUSCODE_BADNOTSUPPORTED; + + /* Set the field identifier */ + fieldMetaData->dataSetFieldId = UA_PubSubManager_generateUniqueGuid(server); + + /* Set the description */ + fieldMetaData->description = UA_LOCALIZEDTEXT_ALLOC("", ""); + + /* Set the name */ + const UA_DataSetVariableConfig *var = &field->config.field.variable; + UA_StatusCode res = UA_String_copy(&var->fieldNameAlias, &fieldMetaData->name); + UA_CHECK_STATUS(res, return res); + + /* Static value source. ToDo after freeze PR, the value source must be + * checked (other behavior for static value source) */ + if(var->rtValueSource.rtFieldSourceEnabled && + !var->rtValueSource.rtInformationModelNode) { + const UA_DataValue *svs = *var->rtValueSource.staticValueSource; + if(svs->value.arrayDimensionsSize > 0) { + fieldMetaData->arrayDimensions = (UA_UInt32 *) + UA_calloc(svs->value.arrayDimensionsSize, sizeof(UA_UInt32)); + if(fieldMetaData->arrayDimensions == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(fieldMetaData->arrayDimensions, svs->value.arrayDimensions, + sizeof(UA_UInt32) * svs->value.arrayDimensionsSize); + } + fieldMetaData->arrayDimensionsSize = svs->value.arrayDimensionsSize; + + res = UA_NodeId_copy(&svs->value.type->typeId, &fieldMetaData->dataType); + UA_CHECK_STATUS(res, return res); + + //TODO collect value rank for the static field source + fieldMetaData->properties = NULL; + fieldMetaData->propertiesSize = 0; + fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE; + return UA_STATUSCODE_GOOD; } + + /* Set the Array Dimensions */ + const UA_PublishedVariableDataType *pp = &var->publishParameters; + UA_Variant value; + UA_Variant_init(&value); + res = UA_Server_readArrayDimensions(server, pp->publishedVariable, &value); + UA_CHECK_STATUS_LOG(res, return res, + WARNING, &server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub meta data generation. Reading the array dimensions failed."); + + if(value.arrayDimensionsSize > 0) { + fieldMetaData->arrayDimensions = (UA_UInt32 *) + UA_calloc(value.arrayDimensionsSize, sizeof(UA_UInt32)); + if(!fieldMetaData->arrayDimensions) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(fieldMetaData->arrayDimensions, value.arrayDimensions, + sizeof(UA_UInt32)*value.arrayDimensionsSize); + } + fieldMetaData->arrayDimensionsSize = value.arrayDimensionsSize; + + /* Set the DataType */ + res = UA_Server_readDataType(server, pp->publishedVariable, + &fieldMetaData->dataType); + UA_CHECK_STATUS_LOG(res, return res, + WARNING, &server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub meta data generation. Reading the datatype failed."); + + if(!UA_NodeId_isNull(&fieldMetaData->dataType)) { + const UA_DataType *currentDataType = + UA_findDataTypeWithCustom(&fieldMetaData->dataType, + server->config.customDataTypes); +#ifdef UA_ENABLE_TYPEDESCRIPTION + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "MetaData creation. Found DataType %s.", currentDataType->typeName); +#endif + /* Check if the datatype is a builtInType, if yes set the builtinType. + * TODO: Remove the magic number */ + if(currentDataType->typeKind <= UA_DATATYPEKIND_ENUM) + fieldMetaData->builtInType = (UA_Byte)currentDataType->typeKind; + } else { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub meta data generation. DataType is UA_NODEID_NULL."); + } + + /* Set the ValueRank */ + UA_Int32 valueRank; + res = UA_Server_readValueRank(server, pp->publishedVariable, &valueRank); + UA_CHECK_STATUS_LOG(res, return res, + WARNING, &server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub meta data generation. Reading the value rank failed."); + fieldMetaData->valueRank = valueRank; + + /* PromotedField? */ + if(var->promotedField) + fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_PROMOTEDFIELD; + else + fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE; + + /* Properties */ + fieldMetaData->properties = NULL; + fieldMetaData->propertiesSize = 0; + + //TODO collect the following fields*/ + //fieldMetaData.builtInType + //fieldMetaData.maxStringLength + + return UA_STATUSCODE_GOOD; } UA_DataSetFieldResult UA_Server_addDataSetField(UA_Server *server, const UA_NodeId publishedDataSet, const UA_DataSetFieldConfig *fieldConfig, UA_NodeId *fieldIdentifier) { - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - UA_DataSetFieldResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, {0, 0}}; - if(!fieldConfig) + UA_DataSetFieldResult result = {0}; + if(!fieldConfig) { + result.result = UA_STATUSCODE_BADINVALIDARGUMENT; return result; + } - UA_PublishedDataSet *currentDataSet = UA_PublishedDataSet_findPDSbyId(server, publishedDataSet); - if(currentDataSet == NULL){ + UA_PublishedDataSet *currDS = + UA_PublishedDataSet_findPDSbyId(server, publishedDataSet); + if(!currDS) { result.result = UA_STATUSCODE_BADNOTFOUND; return result; } - if(currentDataSet->config.configurationFrozen){ + if(currDS->configurationFrozen) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Adding DataSetField failed. PublishedDataSet is frozen."); result.result = UA_STATUSCODE_BADCONFIGURATIONERROR; return result; } - if(currentDataSet->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){ + if(currDS->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS) { result.result = UA_STATUSCODE_BADNOTIMPLEMENTED; return result; } - UA_DataSetField *newField = (UA_DataSetField *) UA_calloc(1, sizeof(UA_DataSetField)); - if(!newField){ + UA_DataSetField *newField = (UA_DataSetField*)UA_calloc(1, sizeof(UA_DataSetField)); + if(!newField) { result.result = UA_STATUSCODE_BADINTERNALERROR; return result; } - UA_DataSetFieldConfig tmpFieldConfig; - retVal |= UA_DataSetFieldConfig_copy(fieldConfig, &tmpFieldConfig); - newField->config = tmpFieldConfig; - UA_PubSubManager_generateUniqueNodeId(server, &newField->identifier); - if(fieldIdentifier != NULL){ - UA_NodeId_copy(&newField->identifier, fieldIdentifier); + UA_StatusCode retVal = UA_DataSetFieldConfig_copy(fieldConfig, &newField->config); + if(retVal != UA_STATUSCODE_GOOD) { + UA_free(newField); + result.result = retVal; + return result; } - newField->publishedDataSet = currentDataSet->identifier; - //update major version of parent published data set - currentDataSet->dataSetMetaData.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference(); - /* The order of DataSetFields should be the same in both creating and publishing. - * So adding DataSetFields at the the end of the DataSets using TAILQ structure */ - if (currentDataSet->fieldSize != 0) - TAILQ_INSERT_TAIL(¤tDataSet->fields, newField, listEntry); - else - TAILQ_INSERT_HEAD(¤tDataSet->fields, newField, listEntry); - if(newField->config.field.variable.promotedField) - currentDataSet->promotedFieldsCount++; - currentDataSet->fieldSize++; - - //generate fieldMetadata within the DataSetMetaData - currentDataSet->dataSetMetaData.fieldsSize++; - UA_FieldMetaData *fieldMetaData = (UA_FieldMetaData *) - UA_realloc(currentDataSet->dataSetMetaData.fields, currentDataSet->dataSetMetaData.fieldsSize * - sizeof(UA_FieldMetaData)); - if(!fieldMetaData){ - result.result = UA_STATUSCODE_BADOUTOFMEMORY; + newField->publishedDataSet = currDS->identifier; + + /* Initialize the field metadata. Also generates a FieldId */ + UA_FieldMetaData fmd; + UA_FieldMetaData_init(&fmd); + result.result = generateFieldMetaData(server, newField, &fmd); + if(result.result != UA_STATUSCODE_GOOD) { + UA_FieldMetaData_clear(&fmd); + UA_DataSetFieldConfig_clear(&newField->config); + UA_free(newField); return result; } - currentDataSet->dataSetMetaData.fields = fieldMetaData; - UA_FieldMetaData_init(&fieldMetaData[currentDataSet->fieldSize-1]); - if(generateFieldMetaData(server, newField, &fieldMetaData[currentDataSet->fieldSize-1]) != UA_STATUSCODE_GOOD){ - UA_Server_removeDataSetField(server, newField->identifier); - result.result = UA_STATUSCODE_BADINTERNALERROR; + /* Append to the metadata fields array. Point of last return. */ + result.result = UA_Array_append((void**)&currDS->dataSetMetaData.fields, + &currDS->dataSetMetaData.fieldsSize, + &fmd, &UA_TYPES[UA_TYPES_FIELDMETADATA]); + if(result.result != UA_STATUSCODE_GOOD) { + UA_FieldMetaData_clear(&fmd); + UA_DataSetFieldConfig_clear(&newField->config); + UA_free(newField); return result; } - UA_DataSetField *dsf; + + /* Copy the identifier from the metadata. Cannot fail with a guid NodeId. */ + newField->identifier = UA_NODEID_GUID(1, fmd.dataSetFieldId); + if(fieldIdentifier) + UA_NodeId_copy(&newField->identifier, fieldIdentifier); + + /* Register the field. The order of DataSetFields should be the same in both + * creating and publishing. So adding DataSetFields at the the end of the + * DataSets using the TAILQ structure. */ + TAILQ_INSERT_TAIL(&currDS->fields, newField, listEntry); + currDS->fieldSize++; + + if(newField->config.field.variable.promotedField) + currDS->promotedFieldsCount++; + + /* The values of the metadata are "borrowed" in a mirrored structure in the + * pds. Reset them after resizing the array. */ size_t counter = 0; - TAILQ_FOREACH(dsf, ¤tDataSet->fields, listEntry){ - dsf->fieldMetaData = fieldMetaData[counter++]; + UA_DataSetField *dsf; + TAILQ_FOREACH(dsf, &currDS->fields, listEntry) { + dsf->fieldMetaData = currDS->dataSetMetaData.fields[counter++]; } - result.result = retVal; - result.configurationVersion.majorVersion = currentDataSet->dataSetMetaData.configurationVersion.majorVersion; - result.configurationVersion.minorVersion = currentDataSet->dataSetMetaData.configurationVersion.minorVersion; + + /* Update major version of parent published data set */ + currDS->dataSetMetaData.configurationVersion.majorVersion = + UA_PubSubConfigurationVersionTimeDifference(); + + result.configurationVersion.majorVersion = + currDS->dataSetMetaData.configurationVersion.majorVersion; + result.configurationVersion.minorVersion = + currDS->dataSetMetaData.configurationVersion.minorVersion; return result; } UA_DataSetFieldResult UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) { + UA_DataSetFieldResult result = {0}; + UA_DataSetField *currentField = UA_DataSetField_findDSFbyId(server, dsf); - UA_DataSetFieldResult result = {UA_STATUSCODE_BADNOTFOUND, {0, 0}}; - if(!currentField) + if(!currentField) { + result.result = UA_STATUSCODE_BADNOTFOUND; return result; + } - if(currentField->config.configurationFrozen){ + if(currentField->configurationFrozen) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Remove DataSetField failed. DataSetField is frozen."); result.result = UA_STATUSCODE_BADCONFIGURATIONERROR; return result; } - UA_PublishedDataSet *parentPublishedDataSet = + UA_PublishedDataSet *pds = UA_PublishedDataSet_findPDSbyId(server, currentField->publishedDataSet); - if(!parentPublishedDataSet) + if(!pds) { + result.result = UA_STATUSCODE_BADNOTFOUND; return result; + } - if(parentPublishedDataSet->config.configurationFrozen){ + if(pds->configurationFrozen) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Remove DataSetField failed. PublishedDataSet is frozen."); result.result = UA_STATUSCODE_BADCONFIGURATIONERROR; return result; } - parentPublishedDataSet->fieldSize--; + /* Reduce the counters before the config is cleaned up */ if(currentField->config.field.variable.promotedField) - parentPublishedDataSet->promotedFieldsCount--; - /* update major version of PublishedDataSet */ - parentPublishedDataSet->dataSetMetaData.configurationVersion.majorVersion = + pds->promotedFieldsCount--; + pds->fieldSize--; + + /* Update major version of PublishedDataSet */ + pds->dataSetMetaData.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference(); + /* Clean up */ currentField->fieldMetaData.arrayDimensions = NULL; currentField->fieldMetaData.properties = NULL; currentField->fieldMetaData.name = UA_STRING_NULL; currentField->fieldMetaData.description.locale = UA_STRING_NULL; currentField->fieldMetaData.description.text = UA_STRING_NULL; UA_DataSetField_clear(currentField); - TAILQ_REMOVE(&parentPublishedDataSet->fields, currentField, listEntry); + + /* Remove */ + TAILQ_REMOVE(&pds->fields, currentField, listEntry); UA_free(currentField); - result.result = UA_STATUSCODE_GOOD; - //regenerate DataSetMetaData - parentPublishedDataSet->dataSetMetaData.fieldsSize--; - if(parentPublishedDataSet->dataSetMetaData.fieldsSize > 0){ - for(size_t i = 0; i < parentPublishedDataSet->dataSetMetaData.fieldsSize+1; i++) { - UA_FieldMetaData_clear(&parentPublishedDataSet->dataSetMetaData.fields[i]); + /* Regenerate DataSetMetaData */ + pds->dataSetMetaData.fieldsSize--; + if(pds->dataSetMetaData.fieldsSize > 0) { + for(size_t i = 0; i < pds->dataSetMetaData.fieldsSize+1; i++) { + UA_FieldMetaData_clear(&pds->dataSetMetaData.fields[i]); } - UA_free(parentPublishedDataSet->dataSetMetaData.fields); + UA_free(pds->dataSetMetaData.fields); UA_FieldMetaData *fieldMetaData = (UA_FieldMetaData *) - UA_calloc(parentPublishedDataSet->dataSetMetaData.fieldsSize, - sizeof(UA_FieldMetaData)); - if(!fieldMetaData){ + UA_calloc(pds->dataSetMetaData.fieldsSize, sizeof(UA_FieldMetaData)); + if(!fieldMetaData) { result.result = UA_STATUSCODE_BADOUTOFMEMORY; return result; } UA_DataSetField *tmpDSF; size_t counter = 0; - TAILQ_FOREACH(tmpDSF, &parentPublishedDataSet->fields, listEntry){ - UA_FieldMetaData tmpFieldMetaData; - UA_FieldMetaData_init(&tmpFieldMetaData); - if(generateFieldMetaData(server, tmpDSF, &tmpFieldMetaData) != UA_STATUSCODE_GOOD){ + TAILQ_FOREACH(tmpDSF, &pds->fields, listEntry){ + result.result = generateFieldMetaData(server, tmpDSF, &fieldMetaData[counter]); + if(result.result != UA_STATUSCODE_GOOD) { + UA_FieldMetaData_clear(&fieldMetaData[counter]); UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "PubSub MetaData generation failed!"); - //TODO how to ensure consistency if the metadata regeneration fails - result.result = UA_STATUSCODE_BADINTERNALERROR; + break; } - fieldMetaData[counter++] = tmpFieldMetaData; + counter++; } - parentPublishedDataSet->dataSetMetaData.fields = fieldMetaData; + pds->dataSetMetaData.fields = fieldMetaData; } else { - UA_FieldMetaData_delete(parentPublishedDataSet->dataSetMetaData.fields); - parentPublishedDataSet->dataSetMetaData.fields = NULL; + UA_FieldMetaData_delete(pds->dataSetMetaData.fields); + pds->dataSetMetaData.fields = NULL; } - result.configurationVersion.majorVersion = parentPublishedDataSet->dataSetMetaData.configurationVersion.majorVersion; - result.configurationVersion.minorVersion = parentPublishedDataSet->dataSetMetaData.configurationVersion.minorVersion; + result.configurationVersion.majorVersion = + pds->dataSetMetaData.configurationVersion.majorVersion; + result.configurationVersion.minorVersion = + pds->dataSetMetaData.configurationVersion.minorVersion; return result; } @@ -28854,13 +28406,14 @@ UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src, retVal |= UA_String_copy(&src->name, &dst->name); retVal |= UA_String_copy(&src->dataSetName, &dst->dataSetName); retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings); - if (src->dataSetWriterPropertiesSize > 0) { + if(src->dataSetWriterPropertiesSize > 0) { dst->dataSetWriterProperties = (UA_KeyValuePair *) UA_calloc(src->dataSetWriterPropertiesSize, sizeof(UA_KeyValuePair)); if(!dst->dataSetWriterProperties) return UA_STATUSCODE_BADOUTOFMEMORY; for(size_t i = 0; i < src->dataSetWriterPropertiesSize; i++){ - retVal |= UA_KeyValuePair_copy(&src->dataSetWriterProperties[i], &dst->dataSetWriterProperties[i]); + retVal |= UA_KeyValuePair_copy(&src->dataSetWriterProperties[i], + &dst->dataSetWriterProperties[i]); } } return retVal; @@ -28868,20 +28421,26 @@ UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src, UA_StatusCode UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw, - UA_DataSetWriterConfig *config){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_DataSetWriterConfig *config) { if(!config) return UA_STATUSCODE_BADINVALIDARGUMENT; - UA_DataSetWriter *currentDataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw); if(!currentDataSetWriter) return UA_STATUSCODE_BADNOTFOUND; + return UA_DataSetWriterConfig_copy(¤tDataSetWriter->config, config); +} - UA_DataSetWriterConfig tmpWriterConfig; - //deep copy of the actual config - retVal |= UA_DataSetWriterConfig_copy(¤tDataSetWriter->config, &tmpWriterConfig); - *config = tmpWriterConfig; - return retVal; +UA_StatusCode +UA_Server_DataSetWriter_getState(UA_Server *server, UA_NodeId dataSetWriterIdentifier, + UA_PubSubState *state) { + if((server == NULL) || (state == NULL)) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_DataSetWriter *currentDataSetWriter = + UA_DataSetWriter_findDSWbyId(server, dataSetWriterIdentifier); + if(currentDataSetWriter == NULL) + return UA_STATUSCODE_BADNOTFOUND; + *state = currentDataSetWriter->state; + return UA_STATUSCODE_GOOD; } UA_DataSetWriter * @@ -28905,7 +28464,7 @@ void UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig) { UA_String_clear(&pdsConfig->name); UA_String_clear(&pdsConfig->dataSetName); - for(size_t i = 0; i < pdsConfig->dataSetWriterPropertiesSize; i++){ + for(size_t i = 0; i < pdsConfig->dataSetWriterPropertiesSize; i++) { UA_KeyValuePair_clear(&pdsConfig->dataSetWriterProperties[i]); } UA_free(pdsConfig->dataSetWriterProperties); @@ -28915,12 +28474,12 @@ UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig) { static void UA_DataSetWriter_clear(UA_Server *server, UA_DataSetWriter *dataSetWriter) { UA_DataSetWriterConfig_clear(&dataSetWriter->config); - //delete DataSetWriter UA_NodeId_clear(&dataSetWriter->identifier); UA_NodeId_clear(&dataSetWriter->linkedWriterGroup); UA_NodeId_clear(&dataSetWriter->connectedDataSet); + + /* Delete lastSamples store */ #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES - //delete lastSamples store for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++) { UA_DataValue_clear(&dataSetWriter->lastSamples[i].value); } @@ -28932,7 +28491,8 @@ UA_DataSetWriter_clear(UA_Server *server, UA_DataSetWriter *dataSetWriter) { //state machine methods not part of the open62541 state machine API UA_StatusCode -UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, UA_DataSetWriter *dataSetWriter) { +UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_DataSetWriter *dataSetWriter) { switch(state){ case UA_PUBSUBSTATE_DISABLED: switch (dataSetWriter->state){ @@ -28944,7 +28504,6 @@ UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, UA_Data break; case UA_PUBSUBSTATE_OPERATIONAL: dataSetWriter->state = UA_PUBSUBSTATE_DISABLED; - break; case UA_PUBSUBSTATE_ERROR: break; @@ -29006,232 +28565,20 @@ UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, UA_Data return UA_STATUSCODE_GOOD; } -/**********************************************/ -/* WriterGroup */ -/**********************************************/ - -UA_StatusCode -UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src, - UA_WriterGroupConfig *dst){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - memcpy(dst, src, sizeof(UA_WriterGroupConfig)); - retVal |= UA_String_copy(&src->name, &dst->name); - retVal |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings); - retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings); - if (src->groupPropertiesSize > 0) { - dst->groupProperties = (UA_KeyValuePair *) UA_calloc(src->groupPropertiesSize, sizeof(UA_KeyValuePair)); - if(!dst->groupProperties) - return UA_STATUSCODE_BADOUTOFMEMORY; - for(size_t i = 0; i < src->groupPropertiesSize; i++){ - retVal |= UA_KeyValuePair_copy(&src->groupProperties[i], &dst->groupProperties[i]); - } - } - return retVal; -} - -UA_StatusCode -UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup, - UA_WriterGroupConfig *config){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - if(!config) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - UA_WriterGroup *currentWriterGroup = UA_WriterGroup_findWGbyId(server, writerGroup); - if(!currentWriterGroup){ - return UA_STATUSCODE_BADNOTFOUND; - } - UA_WriterGroupConfig tmpWriterGroupConfig; - //deep copy of the actual config - retVal |= UA_WriterGroupConfig_copy(¤tWriterGroup->config, &tmpWriterGroupConfig); - *config = tmpWriterGroupConfig; - return retVal; -} - -UA_StatusCode -UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier, - const UA_WriterGroupConfig *config){ - if(!config) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - UA_WriterGroup *currentWriterGroup = UA_WriterGroup_findWGbyId(server, writerGroupIdentifier); - if(!currentWriterGroup) - return UA_STATUSCODE_BADNOTFOUND; - - if(currentWriterGroup->config.configurationFrozen){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Modify WriterGroup failed. WriterGroup is frozen."); - return UA_STATUSCODE_BADCONFIGURATIONERROR; - } - - //The update functionality will be extended during the next PubSub batches. - //Currently is only a change of the publishing interval possible. - if(currentWriterGroup->config.maxEncapsulatedDataSetMessageCount != config->maxEncapsulatedDataSetMessageCount){ - currentWriterGroup->config.maxEncapsulatedDataSetMessageCount = config->maxEncapsulatedDataSetMessageCount; - if(currentWriterGroup->config.messageSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "MaxEncapsulatedDataSetMessag need enabled 'PayloadHeader' within the message settings."); - } - } - if(currentWriterGroup->config.publishingInterval != config->publishingInterval) { - if(currentWriterGroup->config.rtLevel == UA_PUBSUB_RT_NONE && currentWriterGroup->state == UA_PUBSUBSTATE_OPERATIONAL){ - UA_PubSubManager_removeRepeatedPubSubCallback(server, currentWriterGroup->publishCallbackId); - currentWriterGroup->config.publishingInterval = config->publishingInterval; - UA_WriterGroup_addPublishCallback(server, currentWriterGroup); - } else { - currentWriterGroup->config.publishingInterval = config->publishingInterval; - } - } - if(currentWriterGroup->config.priority != config->priority) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "No or unsupported WriterGroup update."); - } - return UA_STATUSCODE_GOOD; -} - -UA_WriterGroup * -UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier){ - UA_PubSubConnection *tmpConnection; - TAILQ_FOREACH(tmpConnection, &server->pubSubManager.connections, listEntry){ - UA_WriterGroup *tmpWriterGroup; - LIST_FOREACH(tmpWriterGroup, &tmpConnection->writerGroups, listEntry) { - if(UA_NodeId_equal(&identifier, &tmpWriterGroup->identifier)){ - return tmpWriterGroup; - } - } - } - return NULL; -} - -void -UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig){ - //delete writerGroup config - UA_String_clear(&writerGroupConfig->name); - UA_ExtensionObject_clear(&writerGroupConfig->transportSettings); - UA_ExtensionObject_clear(&writerGroupConfig->messageSettings); - UA_Array_delete(writerGroupConfig->groupProperties, - writerGroupConfig->groupPropertiesSize, - &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); - writerGroupConfig->groupProperties = NULL; -} - -static void -UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup) { - UA_WriterGroupConfig_clear(&writerGroup->config); - //delete WriterGroup - //delete all writers. Therefore removeDataSetWriter is called from PublishedDataSet - UA_DataSetWriter *dataSetWriter, *tmpDataSetWriter; - LIST_FOREACH_SAFE(dataSetWriter, &writerGroup->writers, listEntry, tmpDataSetWriter){ - UA_Server_removeDataSetWriter(server, dataSetWriter->identifier); - } - if(writerGroup->bufferedMessage.offsetsSize > 0){ - for (size_t i = 0; i < writerGroup->bufferedMessage.offsetsSize; i++) { - if(writerGroup->bufferedMessage.offsets[i].contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT){ - UA_DataValue_delete(writerGroup->bufferedMessage.offsets[i].offsetData.value.value); - } - } - UA_ByteString_deleteMembers(&writerGroup->bufferedMessage.buffer); - UA_free(writerGroup->bufferedMessage.offsets); - } - UA_NodeId_clear(&writerGroup->identifier); -} - -UA_StatusCode -UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, UA_WriterGroup *writerGroup){ - UA_DataSetWriter *dataSetWriter; - switch(state){ - case UA_PUBSUBSTATE_DISABLED: - switch (writerGroup->state){ - case UA_PUBSUBSTATE_DISABLED: - return UA_STATUSCODE_GOOD; - case UA_PUBSUBSTATE_PAUSED: - break; - case UA_PUBSUBSTATE_OPERATIONAL: - UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId); - LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){ - UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, dataSetWriter); - } - writerGroup->state = UA_PUBSUBSTATE_DISABLED; - break; - case UA_PUBSUBSTATE_ERROR: - break; - default: - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Received unknown PubSub state!"); - } - break; - case UA_PUBSUBSTATE_PAUSED: - switch (writerGroup->state){ - case UA_PUBSUBSTATE_DISABLED: - break; - case UA_PUBSUBSTATE_PAUSED: - return UA_STATUSCODE_GOOD; - case UA_PUBSUBSTATE_OPERATIONAL: - break; - case UA_PUBSUBSTATE_ERROR: - break; - default: - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Received unknown PubSub state!"); - } - break; - case UA_PUBSUBSTATE_OPERATIONAL: - switch (writerGroup->state){ - case UA_PUBSUBSTATE_DISABLED: - writerGroup->state = UA_PUBSUBSTATE_OPERATIONAL; - UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId); - LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){ - UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, dataSetWriter); - } - UA_WriterGroup_addPublishCallback(server, writerGroup); - break; - case UA_PUBSUBSTATE_PAUSED: - break; - case UA_PUBSUBSTATE_OPERATIONAL: - return UA_STATUSCODE_GOOD; - case UA_PUBSUBSTATE_ERROR: - break; - default: - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Received unknown PubSub state!"); - } - break; - case UA_PUBSUBSTATE_ERROR: - switch (writerGroup->state){ - case UA_PUBSUBSTATE_DISABLED: - break; - case UA_PUBSUBSTATE_PAUSED: - break; - case UA_PUBSUBSTATE_OPERATIONAL: - break; - case UA_PUBSUBSTATE_ERROR: - return UA_STATUSCODE_GOOD; - default: - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Received unknown PubSub state!"); - } - break; - default: - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Received unknown PubSub state!"); - } - return UA_STATUSCODE_GOOD; -} - - UA_StatusCode UA_Server_addDataSetWriter(UA_Server *server, const UA_NodeId writerGroup, const UA_NodeId dataSet, const UA_DataSetWriterConfig *dataSetWriterConfig, UA_NodeId *writerIdentifier) { - UA_StatusCode retVal = UA_STATUSCODE_GOOD; if(!dataSetWriterConfig) return UA_STATUSCODE_BADINVALIDARGUMENT; - UA_PublishedDataSet *currentDataSetContext = UA_PublishedDataSet_findPDSbyId(server, dataSet); + UA_PublishedDataSet *currentDataSetContext = + UA_PublishedDataSet_findPDSbyId(server, dataSet); if(!currentDataSetContext) return UA_STATUSCODE_BADNOTFOUND; - if(currentDataSetContext->config.configurationFrozen){ + if(currentDataSetContext->configurationFrozen){ UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Adding DataSetWriter failed. PublishedDataSet is frozen."); return UA_STATUSCODE_BADCONFIGURATIONERROR; @@ -29241,16 +28588,17 @@ UA_Server_addDataSetWriter(UA_Server *server, if(!wg) return UA_STATUSCODE_BADNOTFOUND; - if(wg->config.configurationFrozen){ + if(wg->configurationFrozen) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Adding DataSetWriter failed. WriterGroup is frozen."); return UA_STATUSCODE_BADCONFIGURATIONERROR; } - if(wg->config.rtLevel != UA_PUBSUB_RT_NONE){ + if(wg->config.rtLevel != UA_PUBSUB_RT_NONE) { UA_DataSetField *tmpDSF; - TAILQ_FOREACH(tmpDSF, ¤tDataSetContext->fields, listEntry){ - if(tmpDSF->config.field.variable.staticValueSourceEnabled != UA_TRUE){ + TAILQ_FOREACH(tmpDSF, ¤tDataSetContext->fields, listEntry) { + if(!tmpDSF->config.field.variable.rtValueSource.rtFieldSourceEnabled && + !tmpDSF->config.field.variable.rtValueSource.rtInformationModelNode) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Adding DataSetWriter failed. Fields in PDS are not RT capable."); return UA_STATUSCODE_BADCONFIGURATIONERROR; @@ -29258,21 +28606,37 @@ UA_Server_addDataSetWriter(UA_Server *server, } } - UA_DataSetWriter *newDataSetWriter = (UA_DataSetWriter *) UA_calloc(1, sizeof(UA_DataSetWriter)); + UA_DataSetWriter *newDataSetWriter = (UA_DataSetWriter *) + UA_calloc(1, sizeof(UA_DataSetWriter)); if(!newDataSetWriter) return UA_STATUSCODE_BADOUTOFMEMORY; - //copy the config into the new dataSetWriter - UA_DataSetWriterConfig tmpDataSetWriterConfig; - retVal |= UA_DataSetWriterConfig_copy(dataSetWriterConfig, &tmpDataSetWriterConfig); - newDataSetWriter->config = tmpDataSetWriterConfig; - //save the current version of the connected PublishedDataSet - newDataSetWriter->connectedDataSetVersion = currentDataSetContext->dataSetMetaData.configurationVersion; + newDataSetWriter->componentType = UA_PUBSUB_COMPONENT_DATASETWRITER; + + UA_StatusCode res = UA_STATUSCODE_GOOD; + if(wg->state == UA_PUBSUBSTATE_OPERATIONAL) { + res = UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, + newDataSetWriter); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Add DataSetWriter failed. setPubSubState failed."); + UA_free(newDataSetWriter); + return res; + } + } + + /* Copy the config into the new dataSetWriter */ + res = UA_DataSetWriterConfig_copy(dataSetWriterConfig, &newDataSetWriter->config); + UA_CHECK_STATUS(res, UA_free(newDataSetWriter); return res); + + /* Save the current version of the connected PublishedDataSet */ + newDataSetWriter->connectedDataSetVersion = + currentDataSetContext->dataSetMetaData.configurationVersion; #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES - //initialize the queue for the last values - if (currentDataSetContext->fieldSize > 0) { - newDataSetWriter->lastSamples = (UA_DataSetWriterSample * ) + /* Initialize the queue for the last values */ + if(currentDataSetContext->fieldSize > 0) { + newDataSetWriter->lastSamples = (UA_DataSetWriterSample*) UA_calloc(currentDataSetContext->fieldSize, sizeof(UA_DataSetWriterSample)); if(!newDataSetWriter->lastSamples) { UA_DataSetWriterConfig_clear(&newDataSetWriter->config); @@ -29287,28 +28651,55 @@ UA_Server_addDataSetWriter(UA_Server *server, } #endif - //connect PublishedDataSet with DataSetWriter + /* Connect PublishedDataSet with DataSetWriter */ newDataSetWriter->connectedDataSet = currentDataSetContext->identifier; newDataSetWriter->linkedWriterGroup = wg->identifier; - UA_PubSubManager_generateUniqueNodeId(server, &newDataSetWriter->identifier); - if(writerIdentifier != NULL) - UA_NodeId_copy(&newDataSetWriter->identifier, writerIdentifier); - //add the new writer to the group + + /* Add the new writer to the group */ LIST_INSERT_HEAD(&wg->writers, newDataSetWriter, listEntry); wg->writersCount++; + #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - addDataSetWriterRepresentation(server, newDataSetWriter); + res |= addDataSetWriterRepresentation(server, newDataSetWriter); +#else + UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, + &newDataSetWriter->identifier); #endif - return retVal; + if(writerIdentifier) + UA_NodeId_copy(&newDataSetWriter->identifier, writerIdentifier); + return res; } UA_StatusCode -UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw){ +UA_DataSetWriter_remove(UA_Server *server, UA_WriterGroup *linkedWriterGroup, + UA_DataSetWriter *dataSetWriter) { + /* Frozen? */ + if(linkedWriterGroup->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Remove DataSetWriter failed. WriterGroup is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + /* Remove from information model */ +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + removeDataSetWriterRepresentation(server, dataSetWriter); +#endif + + /* Remove DataSetWriter from group */ + UA_DataSetWriter_clear(server, dataSetWriter); + LIST_REMOVE(dataSetWriter, listEntry); + linkedWriterGroup->writersCount--; + UA_free(dataSetWriter); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw) { UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw); if(!dataSetWriter) return UA_STATUSCODE_BADNOTFOUND; - if(dataSetWriter->config.configurationFrozen){ + if(dataSetWriter->configurationFrozen) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Remove DataSetWriter failed. DataSetWriter is frozen."); return UA_STATUSCODE_BADCONFIGURATIONERROR; @@ -29319,164 +28710,152 @@ UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw){ if(!linkedWriterGroup) return UA_STATUSCODE_BADNOTFOUND; - if(linkedWriterGroup->config.configurationFrozen){ - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Remove DataSetWriter failed. WriterGroup is frozen."); - return UA_STATUSCODE_BADCONFIGURATIONERROR; - } - - UA_PublishedDataSet *publishedDataSet = - UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet); - if(!publishedDataSet) - return UA_STATUSCODE_BADNOTFOUND; - - linkedWriterGroup->writersCount--; -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - removeDataSetWriterRepresentation(server, dataSetWriter); -#endif - - //remove DataSetWriter from group - UA_DataSetWriter_clear(server, dataSetWriter); - LIST_REMOVE(dataSetWriter, listEntry); - UA_free(dataSetWriter); - return UA_STATUSCODE_GOOD; + return UA_DataSetWriter_remove(server, linkedWriterGroup, dataSetWriter); } /**********************************************/ /* DataSetField */ /**********************************************/ +static void +UA_DataSetField_clear(UA_DataSetField *field) { + UA_DataSetFieldConfig_clear(&field->config); + UA_NodeId_clear(&field->identifier); + UA_NodeId_clear(&field->publishedDataSet); + UA_FieldMetaData_clear(&field->fieldMetaData); +} + UA_StatusCode -UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, UA_DataSetFieldConfig *dst){ - memcpy(dst, src, sizeof(UA_DataSetFieldConfig)); - if(src->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE) { - UA_String_copy(&src->field.variable.fieldNameAlias, &dst->field.variable.fieldNameAlias); - UA_PublishedVariableDataType_copy(&src->field.variable.publishParameters, - &dst->field.variable.publishParameters); - } else { +UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, + UA_DataSetFieldConfig *dst) { + if(src->dataSetFieldType != UA_PUBSUB_DATASETFIELD_VARIABLE) return UA_STATUSCODE_BADNOTSUPPORTED; - } - - return UA_STATUSCODE_GOOD; + memcpy(dst, src, sizeof(UA_DataSetFieldConfig)); + UA_StatusCode res = UA_STATUSCODE_GOOD; + res |= UA_String_copy(&src->field.variable.fieldNameAlias, + &dst->field.variable.fieldNameAlias); + res |= UA_PublishedVariableDataType_copy(&src->field.variable.publishParameters, + &dst->field.variable.publishParameters); + if(res != UA_STATUSCODE_GOOD) + UA_DataSetFieldConfig_clear(dst); + return res; } UA_StatusCode UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf, UA_DataSetFieldConfig *config) { - UA_StatusCode retVal = UA_STATUSCODE_GOOD; if(!config) return UA_STATUSCODE_BADINVALIDARGUMENT; UA_DataSetField *currentDataSetField = UA_DataSetField_findDSFbyId(server, dsf); if(!currentDataSetField) return UA_STATUSCODE_BADNOTFOUND; - UA_DataSetFieldConfig tmpFieldConfig; - //deep copy of the actual config - retVal |= UA_DataSetFieldConfig_copy(¤tDataSetField->config, &tmpFieldConfig); - *config = tmpFieldConfig; - return retVal; + return UA_DataSetFieldConfig_copy(¤tDataSetField->config, config); } UA_DataSetField * UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier) { UA_PublishedDataSet *tmpPDS; - TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry){ + TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry) { UA_DataSetField *tmpField; - TAILQ_FOREACH(tmpField, &tmpPDS->fields, listEntry){ - if(UA_NodeId_equal(&tmpField->identifier, &identifier)){ + TAILQ_FOREACH(tmpField, &tmpPDS->fields, listEntry) { + if(UA_NodeId_equal(&tmpField->identifier, &identifier)) return tmpField; - } } } return NULL; } void -UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig){ - if(dataSetFieldConfig->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE){ +UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig) { + if(dataSetFieldConfig->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE) { UA_String_clear(&dataSetFieldConfig->field.variable.fieldNameAlias); UA_PublishedVariableDataType_clear(&dataSetFieldConfig->field.variable.publishParameters); } } -static void -UA_DataSetField_clear(UA_DataSetField *field) { - UA_DataSetFieldConfig_clear(&field->config); - //delete DataSetField - UA_NodeId_clear(&field->identifier); - UA_NodeId_clear(&field->publishedDataSet); - UA_FieldMetaData_clear(&field->fieldMetaData); -} - /*********************************************************/ /* PublishValues handling */ /*********************************************************/ -/** - * Compare two variants. Internally used for value change detection. - * - * @return true if the value has changed - */ +/* Compare two variants. Internally used for value change detection. */ #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES static UA_Boolean -valueChangedVariant(UA_Variant *oldValue, UA_Variant *newValue){ - if(! (oldValue && newValue)) +valueChangedVariant(UA_Variant *oldValue, UA_Variant *newValue) { + if(!oldValue || !newValue) return false; - UA_ByteString *oldValueEncoding = UA_ByteString_new(), *newValueEncoding = UA_ByteString_new(); - size_t oldValueEncodingSize, newValueEncodingSize; - oldValueEncodingSize = UA_calcSizeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT]); - newValueEncodingSize = UA_calcSizeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT]); - if((oldValueEncodingSize == 0) || (newValueEncodingSize == 0)) + size_t oldValueEncodingSize = UA_calcSizeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT]); + size_t newValueEncodingSize = UA_calcSizeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT]); + if(oldValueEncodingSize == 0 || newValueEncodingSize == 0) return false; if(oldValueEncodingSize != newValueEncodingSize) return true; - if(UA_ByteString_allocBuffer(oldValueEncoding, oldValueEncodingSize) != UA_STATUSCODE_GOOD) - return false; - - if(UA_ByteString_allocBuffer(newValueEncoding, newValueEncodingSize) != UA_STATUSCODE_GOOD) + UA_ByteString oldValueEncoding = {0}; + UA_StatusCode res = UA_ByteString_allocBuffer(&oldValueEncoding, oldValueEncodingSize); + if(res != UA_STATUSCODE_GOOD) return false; - UA_Byte *bufPosOldValue = oldValueEncoding->data; - const UA_Byte *bufEndOldValue = &oldValueEncoding->data[oldValueEncoding->length]; - UA_Byte *bufPosNewValue = newValueEncoding->data; - const UA_Byte *bufEndNewValue = &newValueEncoding->data[newValueEncoding->length]; - if(UA_encodeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT], - &bufPosOldValue, &bufEndOldValue, NULL, NULL) != UA_STATUSCODE_GOOD){ - return false; - } - if(UA_encodeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT], - &bufPosNewValue, &bufEndNewValue, NULL, NULL) != UA_STATUSCODE_GOOD){ + UA_ByteString newValueEncoding = {0}; + res = UA_ByteString_allocBuffer(&newValueEncoding, newValueEncodingSize); + if(res != UA_STATUSCODE_GOOD) { + UA_ByteString_clear(&oldValueEncoding); return false; } - oldValueEncoding->length = (uintptr_t)bufPosOldValue - (uintptr_t)oldValueEncoding->data; - newValueEncoding->length = (uintptr_t)bufPosNewValue - (uintptr_t)newValueEncoding->data; - UA_Boolean compareResult = !UA_ByteString_equal(oldValueEncoding, newValueEncoding); - UA_ByteString_delete(oldValueEncoding); - UA_ByteString_delete(newValueEncoding); + + UA_Byte *bufPosOldValue = oldValueEncoding.data; + const UA_Byte *bufEndOldValue = &oldValueEncoding.data[oldValueEncoding.length]; + UA_Byte *bufPosNewValue = newValueEncoding.data; + const UA_Byte *bufEndNewValue = &newValueEncoding.data[newValueEncoding.length]; + + UA_Boolean compareResult = false; /* default */ + + res = UA_encodeBinaryInternal(oldValue, &UA_TYPES[UA_TYPES_VARIANT], + &bufPosOldValue, &bufEndOldValue, NULL, NULL); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + + res = UA_encodeBinaryInternal(newValue, &UA_TYPES[UA_TYPES_VARIANT], + &bufPosNewValue, &bufEndNewValue, NULL, NULL); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + + oldValueEncoding.length = (uintptr_t)bufPosOldValue - (uintptr_t)oldValueEncoding.data; + newValueEncoding.length = (uintptr_t)bufPosNewValue - (uintptr_t)newValueEncoding.data; + compareResult = !UA_ByteString_equal(&oldValueEncoding, &newValueEncoding); + + cleanup: + UA_ByteString_clear(&oldValueEncoding); + UA_ByteString_clear(&newValueEncoding); return compareResult; } #endif -/** - * Obtain the latest value for a specific DataSetField. This method is currently - * called inside the DataSetMessage generation process. - */ +/* Obtain the latest value for a specific DataSetField. This method is currently + * called inside the DataSetMessage generation process. */ static void UA_PubSubDataSetField_sampleValue(UA_Server *server, UA_DataSetField *field, UA_DataValue *value) { + UA_PublishedVariableDataType *params = &field->config.field.variable.publishParameters; + /* Read the value */ - if(field->config.field.variable.staticValueSourceEnabled == UA_FALSE){ + if(field->config.field.variable.rtValueSource.rtInformationModelNode) { + const UA_VariableNode *rtNode = (const UA_VariableNode *) + UA_NODESTORE_GET(server, ¶ms->publishedVariable); + *value = **rtNode->valueBackend.backend.external.value; + value->value.storageType = UA_VARIANT_DATA_NODELETE; + UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode); + } else if(field->config.field.variable.rtValueSource.rtFieldSourceEnabled == UA_FALSE){ UA_ReadValueId rvid; UA_ReadValueId_init(&rvid); - rvid.nodeId = field->config.field.variable.publishParameters.publishedVariable; - rvid.attributeId = field->config.field.variable.publishParameters.attributeId; - rvid.indexRange = field->config.field.variable.publishParameters.indexRange; + rvid.nodeId = params->publishedVariable; + rvid.attributeId = params->attributeId; + rvid.indexRange = params->indexRange; *value = UA_Server_read(server, &rvid, UA_TIMESTAMPSTORETURN_BOTH); } else { + *value = **field->config.field.variable.rtValueSource.staticValueSource; value->value.storageType = UA_VARIANT_DATA_NODELETE; - *value = field->config.field.variable.staticValueSource; } } @@ -29502,7 +28881,7 @@ UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_Server *server, dataSetMessage->data.keyFrameData.fieldNames = (UA_String *) UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_STRING]); if(!dataSetMessage->data.keyFrameData.fieldNames) { - UA_DataSetMessage_free(dataSetMessage); + UA_DataSetMessage_clear(dataSetMessage); return UA_STATUSCODE_BADOUTOFMEMORY; } #endif @@ -29577,17 +28956,18 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_Server *server, UA_PubSubDataSetField_sampleValue(server, dsf, &value); /* Check if the value has changed */ - if(valueChangedVariant(&dataSetWriter->lastSamples[counter].value.value, &value.value)) { + UA_DataSetWriterSample *ls = &dataSetWriter->lastSamples[counter]; + if(valueChangedVariant(&ls->value.value, &value.value)) { /* increase fieldCount for current delta message */ dataSetMessage->data.deltaFrameData.fieldCount++; - dataSetWriter->lastSamples[counter].valueChanged = true; + ls->valueChanged = true; /* Update last stored sample */ - UA_DataValue_clear(&dataSetWriter->lastSamples[counter].value); - dataSetWriter->lastSamples[counter].value = value; + UA_DataValue_clear(&ls->value); + ls->value = value; } else { UA_DataValue_clear(&value); - dataSetWriter->lastSamples[counter].valueChanged = false; + ls->valueChanged = false; } counter++; @@ -29637,14 +29017,10 @@ UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_Server *server, } #endif -/** - * Generate a DataSetMessage for the given writer. - * - * @param dataSetWriter ptr to corresponding writer - * @return ptr to generated DataSetMessage - */ -static UA_StatusCode -UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *dataSetMessage, +/* Generate a DataSetMessage for the given writer. */ +UA_StatusCode +UA_DataSetWriter_generateDataSetMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, UA_DataSetWriter *dataSetWriter) { UA_PublishedDataSet *currentDataSet = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet); @@ -29654,57 +29030,32 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da /* Reset the message */ memset(dataSetMessage, 0, sizeof(UA_DataSetMessage)); - /* store messageType to switch between json or uadp (default) */ - UA_UInt16 messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE; - UA_JsonDataSetWriterMessageDataType *jsonDataSetWriterMessageDataType = NULL; - /* The configuration Flags are included * inside the std. defined UA_UadpDataSetWriterMessageDataType */ UA_UadpDataSetWriterMessageDataType defaultUadpConfiguration; - UA_UadpDataSetWriterMessageDataType *dataSetWriterMessageDataType = NULL; - if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED || - dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) && - (dataSetWriter->config.messageSettings.content.decoded.type == - &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE])) { - dataSetWriterMessageDataType = (UA_UadpDataSetWriterMessageDataType *) - dataSetWriter->config.messageSettings.content.decoded.data; - - /* type is UADP */ - messageType = UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE; - } else if((dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED || - dataSetWriter->config.messageSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) && - (dataSetWriter->config.messageSettings.content.decoded.type == - &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE])) { - jsonDataSetWriterMessageDataType = (UA_JsonDataSetWriterMessageDataType *) - dataSetWriter->config.messageSettings.content.decoded.data; - - /* type is JSON */ - messageType = UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE; + UA_UadpDataSetWriterMessageDataType *dsm = NULL; + UA_JsonDataSetWriterMessageDataType *jsonDsm = NULL; + const UA_ExtensionObject *ms = &dataSetWriter->config.messageSettings; + if((ms->encoding == UA_EXTENSIONOBJECT_DECODED || + ms->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) && + ms->content.decoded.type == &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE]) { + dsm = (UA_UadpDataSetWriterMessageDataType*)ms->content.decoded.data; /* type is UADP */ + } else if((ms->encoding == UA_EXTENSIONOBJECT_DECODED || + ms->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) && + ms->content.decoded.type == &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE]) { + jsonDsm = (UA_JsonDataSetWriterMessageDataType*)ms->content.decoded.data; /* type is JSON */ } else { - /* create default flag configuration if no + /* Create default flag configuration if no * UadpDataSetWriterMessageDataType was passed in */ memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetWriterMessageDataType)); defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask) ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP | (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION | (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION); - dataSetWriterMessageDataType = &defaultUadpConfiguration; - } - - /* Sanity-test the configuration */ - if(dataSetWriterMessageDataType && - (dataSetWriterMessageDataType->networkMessageNumber != 0 || - dataSetWriterMessageDataType->dataSetOffset != 0 || - dataSetWriterMessageDataType->configuredSize != 0)) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Static DSM configuration not supported. Using defaults"); - dataSetWriterMessageDataType->networkMessageNumber = 0; - dataSetWriterMessageDataType->dataSetOffset = 0; - dataSetWriterMessageDataType->configuredSize = 0; + dsm = &defaultUadpConfiguration; /* type is UADP */ } - /* The field encoding depends on the flags inside the writer config. - * TODO: This can be moved to the encoding layer. */ + /* The field encoding depends on the flags inside the writer config. */ if(dataSetWriter->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA) { dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_RAWDATA; @@ -29718,84 +29069,97 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT; } - if(messageType == UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE) { + if(dsm) { + /* Sanity-test the configuration */ + if(dsm->networkMessageNumber != 0 || + dsm->dataSetOffset != 0 || + dsm->configuredSize != 0) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Static DSM configuration not supported. Using defaults"); + dsm->networkMessageNumber = 0; + dsm->dataSetOffset = 0; + dsm->configuredSize = 0; + } + /* Std: 'The DataSetMessageContentMask defines the flags for the content * of the DataSetMessage header.' */ - if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)dsm->dataSetMessageContentMask & (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) { dataSetMessage->header.configVersionMajorVersionEnabled = true; dataSetMessage->header.configVersionMajorVersion = currentDataSet->dataSetMetaData.configurationVersion.majorVersion; } - if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)dsm->dataSetMessageContentMask & (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) { dataSetMessage->header.configVersionMinorVersionEnabled = true; dataSetMessage->header.configVersionMinorVersion = currentDataSet->dataSetMetaData.configurationVersion.minorVersion; } - if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)dsm->dataSetMessageContentMask & (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) { dataSetMessage->header.dataSetMessageSequenceNrEnabled = true; dataSetMessage->header.dataSetMessageSequenceNr = dataSetWriter->actualDataSetMessageSequenceCount; } - if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)dsm->dataSetMessageContentMask & (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) { dataSetMessage->header.timestampEnabled = true; dataSetMessage->header.timestamp = UA_DateTime_now(); } + /* TODO: Picoseconds resolution not supported atm */ - if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)dsm->dataSetMessageContentMask & (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) { dataSetMessage->header.picoSecondsIncluded = false; } /* TODO: Statuscode not supported yet */ - if((u64)dataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)dsm->dataSetMessageContentMask & (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS) { - dataSetMessage->header.statusEnabled = false; + dataSetMessage->header.statusEnabled = true; } - } else if(messageType == UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE) { - if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask & + } else if(jsonDsm) { + if((u64)jsonDsm->dataSetMessageContentMask & (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) { dataSetMessage->header.configVersionMajorVersionEnabled = true; dataSetMessage->header.configVersionMajorVersion = currentDataSet->dataSetMetaData.configurationVersion.majorVersion; } - if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)jsonDsm->dataSetMessageContentMask & (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) { dataSetMessage->header.configVersionMinorVersionEnabled = true; dataSetMessage->header.configVersionMinorVersion = currentDataSet->dataSetMetaData.configurationVersion.minorVersion; } - if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)jsonDsm->dataSetMessageContentMask & (u64)UA_JSONDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) { dataSetMessage->header.dataSetMessageSequenceNrEnabled = true; dataSetMessage->header.dataSetMessageSequenceNr = dataSetWriter->actualDataSetMessageSequenceCount; } - if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)jsonDsm->dataSetMessageContentMask & (u64)UA_JSONDATASETMESSAGECONTENTMASK_TIMESTAMP) { dataSetMessage->header.timestampEnabled = true; dataSetMessage->header.timestamp = UA_DateTime_now(); } /* TODO: Statuscode not supported yet */ - if((u64)jsonDataSetWriterMessageDataType->dataSetMessageContentMask & + if((u64)jsonDsm->dataSetMessageContentMask & (u64)UA_JSONDATASETMESSAGECONTENTMASK_STATUS) { - dataSetMessage->header.statusEnabled = false; + dataSetMessage->header.statusEnabled = true; } } /* Set the sequence count. Automatically rolls over to zero */ dataSetWriter->actualDataSetMessageSequenceCount++; - /* JSON does not differ between deltaframes and keyframes, only keyframes are currently used. */ - if(messageType != UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE){ + /* JSON does not differ between deltaframes and keyframes, only keyframes + * are currently used. */ + if(dsm) { #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES /* Check if the PublishedDataSet version has changed -> if yes flush the * lastValue store and send a KeyFrame */ @@ -29807,7 +29171,7 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++) UA_DataValue_clear(&dataSetWriter->lastSamples[i].value); - /* Realloc pds dependent memory */ + /* Realloc PDS dependent memory */ dataSetWriter->lastSamplesCount = currentDataSet->fieldSize; UA_DataSetWriterSample *newSamplesArray = (UA_DataSetWriterSample * ) UA_realloc(dataSetWriter->lastSamples, @@ -29818,8 +29182,10 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da memset(dataSetWriter->lastSamples, 0, sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount); - dataSetWriter->connectedDataSetVersion = currentDataSet->dataSetMetaData.configurationVersion; - UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter); + dataSetWriter->connectedDataSetVersion = + currentDataSet->dataSetMetaData.configurationVersion; + UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, + dataSetWriter); dataSetWriter->deltaFrameCounter = 0; return UA_STATUSCODE_GOOD; } @@ -29829,7 +29195,8 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da * field. */ if(currentDataSet->fieldSize > 1 && dataSetWriter->deltaFrameCounter > 0 && dataSetWriter->deltaFrameCounter <= dataSetWriter->config.keyFrameCount) { - UA_PubSubDataSetWriter_generateDeltaFrameMessage(server, dataSetMessage, dataSetWriter); + UA_PubSubDataSetWriter_generateDeltaFrameMessage(server, dataSetMessage, + dataSetWriter); dataSetWriter->deltaFrameCounter++; return UA_STATUSCODE_GOOD; } @@ -29838,58 +29205,799 @@ UA_DataSetWriter_generateDataSetMessage(UA_Server *server, UA_DataSetMessage *da #endif } - return UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, dataSetWriter); + return UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage, + dataSetWriter); } +#endif /* UA_ENABLE_PUBSUB */ + +/**** amalgamated original file "/src/pubsub/ua_pubsub_writergroup.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner) + * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes) + */ + + +#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ + + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL +#endif + +#define UA_MAX_STACKBUF 128 /* Max size of network messages on the stack */ + +static void +UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup); + static UA_StatusCode -sendNetworkMessageJson(UA_PubSubConnection *connection, UA_DataSetMessage *dsm, - UA_UInt16 *writerIds, UA_Byte dsmCount, - UA_ExtensionObject *transportSettings) { - UA_StatusCode retval = UA_STATUSCODE_BADNOTSUPPORTED; +generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg, + UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount, + UA_ExtensionObject *messageSettings, + UA_ExtensionObject *transportSettings, + UA_NetworkMessage *networkMessage); + +UA_StatusCode +UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection, + const UA_WriterGroupConfig *writerGroupConfig, + UA_NodeId *writerGroupIdentifier) { + if(!writerGroupConfig) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + /* Search the connection by the given connectionIdentifier */ + UA_PubSubConnection *currentConnectionContext = + UA_PubSubConnection_findConnectionbyId(server, connection); + if(!currentConnectionContext) + return UA_STATUSCODE_BADNOTFOUND; + + if(currentConnectionContext->configurationFrozen){ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Adding WriterGroup failed. PubSubConnection is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + /* Validate messageSettings type */ + const UA_ExtensionObject *ms = &writerGroupConfig->messageSettings; + if(ms->content.decoded.type) { + if(writerGroupConfig->encodingMimeType == UA_PUBSUB_ENCODING_JSON && + (ms->encoding != UA_EXTENSIONOBJECT_DECODED || + ms->content.decoded.type != &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE])) { + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + if(writerGroupConfig->encodingMimeType == UA_PUBSUB_ENCODING_UADP && + (ms->encoding != UA_EXTENSIONOBJECT_DECODED || + ms->content.decoded.type != &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])) { + return UA_STATUSCODE_BADTYPEMISMATCH; + } + } + + /* Allocate new WriterGroup */ + UA_WriterGroup *newWriterGroup = (UA_WriterGroup*)UA_calloc(1, sizeof(UA_WriterGroup)); + if(!newWriterGroup) + return UA_STATUSCODE_BADOUTOFMEMORY; + + newWriterGroup->componentType = UA_PUBSUB_COMPONENT_WRITERGROUP; + newWriterGroup->linkedConnection = currentConnectionContext; + + /* Deep copy of the config */ + UA_WriterGroupConfig *newConfig = &newWriterGroup->config; + UA_StatusCode res = UA_WriterGroupConfig_copy(writerGroupConfig, newConfig); + if(res != UA_STATUSCODE_GOOD) { + UA_free(newWriterGroup); + return res; + } + + /* Create the datatype value if not present */ + if(!newConfig->messageSettings.content.decoded.type) { + UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new(); + newConfig->messageSettings.content.decoded.data = wgm; + newConfig->messageSettings.content.decoded.type = + &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]; + newConfig->messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED; + } + + /* Attach to the connection */ + LIST_INSERT_HEAD(¤tConnectionContext->writerGroups, newWriterGroup, listEntry); + currentConnectionContext->writerGroupsSize++; + + /* Add representation / create unique identifier */ +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + res = addWriterGroupRepresentation(server, newWriterGroup); +#else + UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, + &newWriterGroup->identifier); +#endif + if(writerGroupIdentifier) + UA_NodeId_copy(&newWriterGroup->identifier, writerGroupIdentifier); + return res; +} + +UA_StatusCode +UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!wg) + return UA_STATUSCODE_BADNOTFOUND; + + if(wg->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Delete WriterGroup failed. WriterGroup is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + UA_PubSubConnection *connection = wg->linkedConnection; + if(!connection) + return UA_STATUSCODE_BADNOTFOUND; + + if(connection->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Delete WriterGroup failed. PubSubConnection is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + if(wg->state == UA_PUBSUBSTATE_OPERATIONAL) { + /* Unregister the publish callback */ + if(wg->config.pubsubManagerCallback.removeCustomCallback) + wg->config.pubsubManagerCallback. + removeCustomCallback(server, wg->identifier, wg->publishCallbackId); + else + UA_PubSubManager_removeRepeatedPubSubCallback(server, wg->publishCallbackId); + + } + + UA_DataSetWriter *dsw, *dsw_tmp; + LIST_FOREACH_SAFE(dsw, &wg->writers, listEntry, dsw_tmp) { + UA_DataSetWriter_remove(server, wg, dsw); + } + + connection->writerGroupsSize--; +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + removeGroupRepresentation(server, wg); +#endif + + UA_WriterGroup_clear(server, wg); + LIST_REMOVE(wg, listEntry); + UA_free(wg); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_freezeWriterGroupConfiguration(UA_Server *server, + const UA_NodeId writerGroup) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!wg) + return UA_STATUSCODE_BADNOTFOUND; + + /* PubSubConnection freezeCounter++ */ + UA_PubSubConnection *pubSubConnection = wg->linkedConnection; + pubSubConnection->configurationFreezeCounter++; + pubSubConnection->configurationFrozen = true; + + /* WriterGroup freeze */ + wg->configurationFrozen = true; + + /* DataSetWriter freeze */ + UA_DataSetWriter *dataSetWriter; + LIST_FOREACH(dataSetWriter, &wg->writers, listEntry) { + dataSetWriter->configurationFrozen = true; + /* PublishedDataSet freezeCounter++ */ + UA_PublishedDataSet *publishedDataSet = + UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet); + publishedDataSet->configurationFreezeCounter++; + publishedDataSet->configurationFrozen = true; + /* DataSetFields freeze */ + UA_DataSetField *dataSetField; + TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry) { + dataSetField->configurationFrozen = true; + } + } + + if(wg->config.rtLevel != UA_PUBSUB_RT_FIXED_SIZE) + return UA_STATUSCODE_GOOD; + + /* Freeze the RT writer configuration */ + size_t dsmCount = 0; + if(wg->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: Non-RT capable encoding."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + + //TODO Clarify: should we only allow = maxEncapsulatedDataSetMessageCount == 1 with RT? + //TODO Clarify: Behaviour if the finale size is more than MTU + + /* Generate data set messages */ + UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount); + UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount); + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_DataSetWriter *dsw; + LIST_FOREACH(dsw, &wg->writers, listEntry) { + /* Find the dataset */ + UA_PublishedDataSet *pds = + UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet); + if(!pds) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub Publish: PublishedDataSet not found"); + continue; + } + if(pds->promotedFieldsCount > 0) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: PDS contains promoted fields."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + + /* Test the DataSetFields */ + UA_DataSetField *dsf; + TAILQ_FOREACH(dsf, &pds->fields, listEntry) { + const UA_VariableNode *rtNode = (const UA_VariableNode *) + UA_NODESTORE_GET(server, &dsf->config.field.variable.publishParameters.publishedVariable); + if(rtNode != NULL && rtNode->valueBackend.backendType != UA_VALUEBACKENDTYPE_EXTERNAL) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: PDS contains field without external data source."); + UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode); + if((UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_STRING].typeId) || + UA_NodeId_equal(&dsf->fieldMetaData.dataType, + &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) && + dsf->fieldMetaData.maxStringLength == 0) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: " + "PDS contains String/ByteString with dynamic length."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } else if(!UA_DataType_isNumeric(UA_findDataType(&dsf->fieldMetaData.dataType)) && + !UA_NodeId_equal(&dsf->fieldMetaData.dataType, &UA_TYPES[UA_TYPES_BOOLEAN].typeId)) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: " + "PDS contains variable with dynamic size."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + } + + /* Generate the DSM */ + res = UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub RT Offset calculation: DataSetMessage buffering failed"); + continue; + } + + dsWriterIds[dsmCount] = dsw->config.dataSetWriterId; + dsmCount++; + } + + /* Define variables here for goto */ + size_t msgSize; + UA_ByteString buf; + UA_NetworkMessage networkMessage; + const UA_Byte *bufEnd; + UA_Byte *bufPos; + + if(res != UA_STATUSCODE_GOOD) + goto cleanup_dsm; + + memset(&networkMessage, 0, sizeof(networkMessage)); + res = generateNetworkMessage(pubSubConnection, wg, dsmStore, dsWriterIds, + (UA_Byte) dsmCount, &wg->config.messageSettings, + &wg->config.transportSettings, &networkMessage); + if(res != UA_STATUSCODE_GOOD) + goto cleanup_dsm; + + memset(&wg->bufferedMessage, 0, sizeof(UA_NetworkMessageOffsetBuffer)); + UA_NetworkMessage_calcSizeBinary(&networkMessage, &wg->bufferedMessage); + + /* Allocate the buffer. Allocate on the stack if the buffer is small. */ + msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage, NULL); + res = UA_ByteString_allocBuffer(&buf, msgSize); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + wg->bufferedMessage.buffer = buf; + + /* Encode the NetworkMessage */ + bufEnd = &wg->bufferedMessage.buffer.data[wg->bufferedMessage.buffer.length]; + bufPos = wg->bufferedMessage.buffer.data; + UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd, NULL); + + cleanup: + UA_free(networkMessage.payload.dataSetPayload.sizes); + + /* Clean up DSM */ + cleanup_dsm: + for(size_t i = 0; i < dsmCount; i++){ + UA_free(dsmStore[i].data.keyFrameData.dataSetFields); +#ifdef UA_ENABLE_JSON_ENCODING + UA_Array_delete(dsmStore[i].data.keyFrameData.fieldNames, + dsmStore[i].data.keyFrameData.fieldCount, + &UA_TYPES[UA_TYPES_STRING]); +#endif + } + + return res; +} + +UA_StatusCode +UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server, + const UA_NodeId writerGroup) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!wg) + return UA_STATUSCODE_BADNOTFOUND; + //if(wg->config.rtLevel == UA_PUBSUB_RT_NONE){ + // UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + // "PubSub configuration freeze without RT configuration has no effect."); + // return UA_STATUSCODE_BADCONFIGURATIONERROR; + //} + //PubSubConnection freezeCounter-- + UA_PubSubConnection *pubSubConnection = wg->linkedConnection; + pubSubConnection->configurationFreezeCounter--; + if(pubSubConnection->configurationFreezeCounter == 0){ + pubSubConnection->configurationFrozen = UA_FALSE; + } + //WriterGroup unfreeze + wg->configurationFrozen = UA_FALSE; + //DataSetWriter unfreeze + UA_DataSetWriter *dataSetWriter; + LIST_FOREACH(dataSetWriter, &wg->writers, listEntry) { + UA_PublishedDataSet *publishedDataSet = + UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet); + //PublishedDataSet freezeCounter-- + publishedDataSet->configurationFreezeCounter--; + if(publishedDataSet->configurationFreezeCounter == 0){ + publishedDataSet->configurationFrozen = UA_FALSE; + UA_DataSetField *dataSetField; + TAILQ_FOREACH(dataSetField, &publishedDataSet->fields, listEntry){ + dataSetField->configurationFrozen = UA_FALSE; + } + } + dataSetWriter->configurationFrozen = UA_FALSE; + } + if(wg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) + UA_ByteString_clear(&wg->bufferedMessage.buffer); + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_setWriterGroupOperational(UA_Server *server, + const UA_NodeId writerGroup) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!wg) + return UA_STATUSCODE_BADNOTFOUND; + return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, wg); +} + +UA_StatusCode +UA_Server_setWriterGroupDisabled(UA_Server *server, + const UA_NodeId writerGroup) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!wg) + return UA_STATUSCODE_BADNOTFOUND; + return UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, wg); +} + +UA_StatusCode +UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src, + UA_WriterGroupConfig *dst){ + UA_StatusCode res = UA_STATUSCODE_GOOD; + memcpy(dst, src, sizeof(UA_WriterGroupConfig)); + res |= UA_String_copy(&src->name, &dst->name); + res |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings); + res |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings); + if(src->groupPropertiesSize > 0) { + dst->groupProperties = (UA_KeyValuePair*) + UA_calloc(src->groupPropertiesSize, sizeof(UA_KeyValuePair)); + if(!dst->groupProperties) + return UA_STATUSCODE_BADOUTOFMEMORY; + for(size_t i = 0; i < src->groupPropertiesSize; i++) { + res |= UA_KeyValuePair_copy(&src->groupProperties[i], &dst->groupProperties[i]); + } + } + if(res != UA_STATUSCODE_GOOD) + UA_WriterGroupConfig_clear(dst); + return res; +} + +UA_StatusCode +UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup, + UA_WriterGroupConfig *config) { + if(!config) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_WriterGroup *currentWG = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!currentWG) + return UA_STATUSCODE_BADNOTFOUND; + return UA_WriterGroupConfig_copy(¤tWG->config, config); +} + +UA_StatusCode +UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier, + const UA_WriterGroupConfig *config){ + if(!config) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + UA_WriterGroup *currentWriterGroup = + UA_WriterGroup_findWGbyId(server, writerGroupIdentifier); + if(!currentWriterGroup) + return UA_STATUSCODE_BADNOTFOUND; + + if(currentWriterGroup->configurationFrozen){ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Modify WriterGroup failed. WriterGroup is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + //The update functionality will be extended during the next PubSub batches. + //Currently is only a change of the publishing interval possible. + if(currentWriterGroup->config.maxEncapsulatedDataSetMessageCount != config->maxEncapsulatedDataSetMessageCount) { + currentWriterGroup->config.maxEncapsulatedDataSetMessageCount = config->maxEncapsulatedDataSetMessageCount; + if(currentWriterGroup->config.messageSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "MaxEncapsulatedDataSetMessag need enabled 'PayloadHeader' within the message settings."); + } + } + + if(currentWriterGroup->config.publishingInterval != config->publishingInterval) { + if(currentWriterGroup->config.rtLevel == UA_PUBSUB_RT_NONE && + currentWriterGroup->state == UA_PUBSUBSTATE_OPERATIONAL) { + if(currentWriterGroup->config.pubsubManagerCallback.removeCustomCallback) + currentWriterGroup->config.pubsubManagerCallback. + removeCustomCallback(server, currentWriterGroup->identifier, + currentWriterGroup->publishCallbackId); + else + UA_PubSubManager_removeRepeatedPubSubCallback(server, currentWriterGroup->publishCallbackId); + + currentWriterGroup->config.publishingInterval = config->publishingInterval; + UA_WriterGroup_addPublishCallback(server, currentWriterGroup); + } else { + currentWriterGroup->config.publishingInterval = config->publishingInterval; + } + } + + if(currentWriterGroup->config.priority != config->priority) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "No or unsupported WriterGroup update."); + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_WriterGroup_getState(UA_Server *server, UA_NodeId writerGroupIdentifier, + UA_PubSubState *state) { + if((server == NULL) || (state == NULL)) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_WriterGroup *currentWriterGroup = + UA_WriterGroup_findWGbyId(server, writerGroupIdentifier); + if(currentWriterGroup == NULL) + return UA_STATUSCODE_BADNOTFOUND; + *state = currentWriterGroup->state; + return UA_STATUSCODE_GOOD; +} + +UA_WriterGroup * +UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier) { + UA_PubSubConnection *tmpConnection; + TAILQ_FOREACH(tmpConnection, &server->pubSubManager.connections, listEntry) { + UA_WriterGroup *tmpWriterGroup; + LIST_FOREACH(tmpWriterGroup, &tmpConnection->writerGroups, listEntry) { + if(UA_NodeId_equal(&identifier, &tmpWriterGroup->identifier)) + return tmpWriterGroup; + } + } + return NULL; +} + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION +UA_StatusCode +UA_Server_setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup, + UA_UInt32 securityTokenId, + const UA_ByteString signingKey, + const UA_ByteString encryptingKey, + const UA_ByteString keyNonce) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup); + if(!wg) + return UA_STATUSCODE_BADNOTFOUND; + + if(!wg->config.securityPolicy) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "No SecurityPolicy configured for the WriterGroup"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + if(securityTokenId != wg->securityTokenId) { + wg->securityTokenId = securityTokenId; + wg->nonceSequenceNumber = 1; + } + + /* Create a new context */ + if(!wg->securityPolicyContext) { + return wg->config.securityPolicy-> + newContext(wg->config.securityPolicy->policyContext, + &signingKey, &encryptingKey, &keyNonce, + &wg->securityPolicyContext); + } + + /* Update the context */ + return wg->config.securityPolicy-> + setSecurityKeys(wg->securityPolicyContext, &signingKey, &encryptingKey, &keyNonce); +} +#endif + +void +UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig){ + UA_String_clear(&writerGroupConfig->name); + UA_ExtensionObject_clear(&writerGroupConfig->transportSettings); + UA_ExtensionObject_clear(&writerGroupConfig->messageSettings); + UA_Array_delete(writerGroupConfig->groupProperties, + writerGroupConfig->groupPropertiesSize, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + writerGroupConfig->groupProperties = NULL; +} + +static void +UA_WriterGroup_clear(UA_Server *server, UA_WriterGroup *writerGroup) { + UA_WriterGroupConfig_clear(&writerGroup->config); + UA_NodeId_clear(&writerGroup->identifier); + + /* Delete all writers */ + UA_DataSetWriter *dataSetWriter, *tmpDataSetWriter; + LIST_FOREACH_SAFE(dataSetWriter, &writerGroup->writers, listEntry, tmpDataSetWriter){ + UA_Server_removeDataSetWriter(server, dataSetWriter->identifier); + } + + if(writerGroup->bufferedMessage.offsetsSize > 0){ + for(size_t i = 0; i < writerGroup->bufferedMessage.offsetsSize; i++) { + if((writerGroup->bufferedMessage.offsets[i].contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT) || + (writerGroup->bufferedMessage.offsets[i].contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW)) { + UA_DataValue_delete(writerGroup->bufferedMessage.offsets[i].offsetData.value.value); + } else if(writerGroup->bufferedMessage.offsets[i].contentType == UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING) { + writerGroup->bufferedMessage.offsets[i].offsetData.value.value->value.data = NULL; + UA_DataValue_delete(writerGroup->bufferedMessage.offsets[i].offsetData.value.value); + } + } + UA_ByteString_clear(&writerGroup->bufferedMessage.buffer); + UA_free(writerGroup->bufferedMessage.offsets); + } + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + if(writerGroup->config.securityPolicy && writerGroup->securityPolicyContext) { + writerGroup->config.securityPolicy->deleteContext(writerGroup->securityPolicyContext); + writerGroup->securityPolicyContext = NULL; + } +#endif +} + +UA_StatusCode +UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_WriterGroup *writerGroup) { + UA_DataSetWriter *dataSetWriter; + switch(state) { + case UA_PUBSUBSTATE_DISABLED: + switch (writerGroup->state){ + case UA_PUBSUBSTATE_DISABLED: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_PAUSED: + break; + case UA_PUBSUBSTATE_OPERATIONAL: + if(writerGroup->config.pubsubManagerCallback.removeCustomCallback) + writerGroup->config.pubsubManagerCallback. + removeCustomCallback(server, writerGroup->identifier, writerGroup->publishCallbackId); + else + UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId); + + LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){ + UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, dataSetWriter); + } + writerGroup->state = UA_PUBSUBSTATE_DISABLED; + break; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + } + break; + case UA_PUBSUBSTATE_PAUSED: + switch (writerGroup->state) { + case UA_PUBSUBSTATE_DISABLED: + break; + case UA_PUBSUBSTATE_PAUSED: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_OPERATIONAL: + break; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + } + break; + case UA_PUBSUBSTATE_OPERATIONAL: + switch (writerGroup->state) { + case UA_PUBSUBSTATE_DISABLED: + writerGroup->state = UA_PUBSUBSTATE_OPERATIONAL; + if(writerGroup->config.pubsubManagerCallback.removeCustomCallback) + writerGroup->config.pubsubManagerCallback. + removeCustomCallback(server, writerGroup->identifier, + writerGroup->publishCallbackId); + else + UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId); + + LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){ + UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, + dataSetWriter); + } + UA_WriterGroup_addPublishCallback(server, writerGroup); + break; + case UA_PUBSUBSTATE_PAUSED: + break; + case UA_PUBSUBSTATE_OPERATIONAL: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + } + break; + case UA_PUBSUBSTATE_ERROR: { + switch (writerGroup->state){ + case UA_PUBSUBSTATE_DISABLED: + break; + case UA_PUBSUBSTATE_PAUSED: + break; + case UA_PUBSUBSTATE_OPERATIONAL: + UA_PubSubManager_removeRepeatedPubSubCallback(server, writerGroup->publishCallbackId); + LIST_FOREACH(dataSetWriter, &writerGroup->writers, listEntry){ + UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dataSetWriter); + } + break; + case UA_PUBSUBSTATE_ERROR: + return UA_STATUSCODE_GOOD; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + } + writerGroup->state = UA_PUBSUBSTATE_ERROR; + /* TODO: WIP - example usage of pubsubStateChangeCallback -> inform + * application about error state, reason param necessary */ + UA_ServerConfig *pConfig = UA_Server_getConfig(server); + if(pConfig->pubSubConfig.stateChangeCallback != 0) { + pConfig->pubSubConfig. + stateChangeCallback(&writerGroup->identifier, UA_PUBSUBSTATE_ERROR, + UA_STATUSCODE_BADINTERNALERROR); + } + break; + } + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + } + return UA_STATUSCODE_GOOD; +} + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION +static UA_StatusCode +encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm, + UA_Byte *signStart, UA_Byte *encryptStart, + UA_Byte *msgEnd) { + UA_StatusCode rv; + void *channelContext = wg->securityPolicyContext; + + if(nm->securityHeader.networkMessageEncrypted) { + /* Set the temporary MessageNonce in the SecurityPolicy */ + rv = wg->config.securityPolicy->setMessageNonce(channelContext, + &nm->securityHeader.messageNonce); + UA_CHECK_STATUS(rv, return rv); + + /* The encryption is done in-place, no need to encode again */ + UA_ByteString toBeEncrypted = + {(uintptr_t)msgEnd - (uintptr_t)encryptStart, encryptStart}; + rv = wg->config.securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(channelContext, &toBeEncrypted); + UA_CHECK_STATUS(rv, return rv); + } + + if(nm->securityHeader.networkMessageSigned) { + UA_ByteString toBeSigned = {(uintptr_t)msgEnd - (uintptr_t)signStart, + signStart}; + + size_t sigSize = wg->config.securityPolicy->symmetricModule.cryptoModule. + signatureAlgorithm.getLocalSignatureSize(channelContext); + UA_ByteString signature = {sigSize, msgEnd}; + + rv = wg->config.securityPolicy->symmetricModule.cryptoModule. + signatureAlgorithm.sign(channelContext, &toBeSigned, &signature); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} +#endif + +static UA_StatusCode +encodeNetworkMessage(UA_WriterGroup *wg, UA_NetworkMessage *nm, + UA_ByteString *buf) { + UA_Byte *bufPos = buf->data; + UA_Byte *bufEnd = &buf->data[buf->length]; + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_Byte *networkMessageStart = bufPos; +#endif + UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(nm, &bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_Byte *payloadStart = bufPos; +#endif + rv = UA_NetworkMessage_encodePayload(nm, &bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_encodeFooters(nm, &bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + /* Encrypt and Sign the message */ + UA_Byte *footerEnd = bufPos; + rv = encryptAndSign(wg, nm, networkMessageStart, payloadStart, footerEnd); + UA_CHECK_STATUS(rv, return rv); +#endif + + return UA_STATUSCODE_GOOD; +} + #ifdef UA_ENABLE_JSON_ENCODING +static UA_StatusCode +sendNetworkMessageJson(UA_PubSubConnection *connection, UA_WriterGroup *wg, + UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) { + /* Prepare the NetworkMessage */ UA_NetworkMessage nm; memset(&nm, 0, sizeof(UA_NetworkMessage)); nm.version = 1; nm.networkMessageType = UA_NETWORKMESSAGE_DATASET; nm.payloadHeaderEnabled = true; - nm.payloadHeader.dataSetPayloadHeader.count = dsmCount; nm.payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds; nm.payload.dataSetPayload.dataSetMessages = dsm; + /* Compute the message length */ + size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, NULL, 0, NULL, 0, true); + /* Allocate the buffer. Allocate on the stack if the buffer is small. */ UA_ByteString buf; - size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, NULL, 0, NULL, 0, true); - size_t stackSize = 1; - if(msgSize <= UA_MAX_STACKBUF) - stackSize = msgSize; - UA_STACKARRAY(UA_Byte, stackBuf, stackSize); + UA_Byte stackBuf[UA_MAX_STACKBUF]; buf.data = stackBuf; buf.length = msgSize; + UA_StatusCode res = UA_STATUSCODE_GOOD; if(msgSize > UA_MAX_STACKBUF) { - retval = UA_ByteString_allocBuffer(&buf, msgSize); - if(retval != UA_STATUSCODE_GOOD) - return retval; + res = UA_ByteString_allocBuffer(&buf, msgSize); + if(res != UA_STATUSCODE_GOOD) + return res; } /* Encode the message */ UA_Byte *bufPos = buf.data; - memset(bufPos, 0, msgSize); - const UA_Byte *bufEnd = &buf.data[buf.length]; - retval = UA_NetworkMessage_encodeJson(&nm, &bufPos, &bufEnd, NULL, 0, NULL, 0, true); - if(retval != UA_STATUSCODE_GOOD) { - if(msgSize > UA_MAX_STACKBUF) - UA_ByteString_clear(&buf); - return retval; - } + const UA_Byte *bufEnd = &buf.data[msgSize]; + res = UA_NetworkMessage_encodeJson(&nm, &bufPos, &bufEnd, NULL, 0, NULL, 0, true); + if(res != UA_STATUSCODE_GOOD) + goto cleanup; + UA_assert(bufPos == bufEnd); /* Send the prepared messages */ - retval = connection->channel->send(connection->channel, transportSettings, &buf); + res = connection->channel->send(connection->channel, + &wg->config.transportSettings, &buf); + + cleanup: if(msgSize > UA_MAX_STACKBUF) UA_ByteString_clear(&buf); -#endif - return retval; + return res; } +#endif static UA_StatusCode generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg, @@ -29936,19 +30044,56 @@ generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg, networkMessage->promotedFieldsEnabled = ((u64)wgm->networkMessageContentMask & (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PROMOTEDFIELDS) != 0; + + /* Set the SecurityHeader */ +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) { + networkMessage->securityEnabled = true; + networkMessage->securityHeader.networkMessageSigned = true; + if(wg->config.securityMode >= UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + networkMessage->securityHeader.networkMessageEncrypted = true; + networkMessage->securityHeader.securityTokenId = wg->securityTokenId; + + /* Generate the MessageNonce */ + UA_ByteString_allocBuffer(&networkMessage->securityHeader.messageNonce, 8); + if(networkMessage->securityHeader.messageNonce.length == 0) + return UA_STATUSCODE_BADOUTOFMEMORY; + + networkMessage->securityHeader.messageNonce.length = 4; /* Generate 4 random bytes */ + UA_StatusCode rv = wg->config.securityPolicy->symmetricModule. + generateNonce(wg->config.securityPolicy->policyContext, + &networkMessage->securityHeader.messageNonce); + if(rv != UA_STATUSCODE_GOOD) + return rv; + networkMessage->securityHeader.messageNonce.length = 8; + UA_Byte *pos = &networkMessage->securityHeader.messageNonce.data[4]; + const UA_Byte *end = &networkMessage->securityHeader.messageNonce.data[8]; + UA_UInt32_encodeBinary(&wg->nonceSequenceNumber, &pos, end); + } +#endif + networkMessage->version = 1; networkMessage->networkMessageType = UA_NETWORKMESSAGE_DATASET; if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_NUMERIC) { networkMessage->publisherIdType = UA_PUBLISHERDATATYPE_UINT16; - networkMessage->publisherId.publisherIdUInt32 = connection->config->publisherId.numeric; - } else if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING){ + networkMessage->publisherId.publisherIdUInt32 = + connection->config->publisherId.numeric; + } else if(connection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) { networkMessage->publisherIdType = UA_PUBLISHERDATATYPE_STRING; - networkMessage->publisherId.publisherIdString = connection->config->publisherId.string; + networkMessage->publisherId.publisherIdString = + connection->config->publisherId.string; } + if(networkMessage->groupHeader.sequenceNumberEnabled) networkMessage->groupHeader.sequenceNumber = wg->sequenceNumber; + + if(networkMessage->groupHeader.groupVersionEnabled) + networkMessage->groupHeader.groupVersion = wgm->groupVersion; + /* Compute the length of the dsm separately for the header */ - UA_STACKARRAY(UA_UInt16, dsmLengths, dsmCount); + UA_UInt16 *dsmLengths = (UA_UInt16 *) UA_calloc(dsmCount, sizeof(UA_UInt16)); + if(!dsmLengths) + return UA_STATUSCODE_BADOUTOFMEMORY; for(UA_Byte i = 0; i < dsmCount; i++) dsmLengths[i] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsm[i], NULL, 0); @@ -29963,58 +30108,115 @@ generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg, } static UA_StatusCode -sendBufferedNetworkMessage(UA_Server *server, UA_PubSubConnection *connection, - UA_NetworkMessageOffsetBuffer *buffer, - UA_ExtensionObject *transportSettings) { - if(UA_NetworkMessage_updateBufferedMessage(buffer) != UA_STATUSCODE_GOOD) - UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub sending. Unknown field type."); - return connection->channel->send(connection->channel, - transportSettings, &buffer->buffer); -} - -static UA_StatusCode -sendNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg, - UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount, - UA_ExtensionObject *messageSettings, - UA_ExtensionObject *transportSettings) { +sendNetworkMessageBinary(UA_PubSubConnection *connection, UA_WriterGroup *wg, + UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) { UA_NetworkMessage nm; memset(&nm, 0, sizeof(UA_NetworkMessage)); - generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount, - messageSettings, transportSettings, &nm); + + /* Fill the message structure */ + UA_StatusCode rv = + generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount, + &wg->config.messageSettings, + &wg->config.transportSettings, &nm); + UA_CHECK_STATUS(rv, return rv); + + /* Compute the message size. Add the overhead for the security signature. + * There is no padding and the encryption incurs no size overhead. */ + size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, NULL); +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) { + UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy; + msgSize += sp->symmetricModule.cryptoModule. + signatureAlgorithm.getLocalSignatureSize(sp->policyContext); + } +#endif /* Allocate the buffer. Allocate on the stack if the buffer is small. */ UA_ByteString buf; - size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, NULL); - size_t stackSize = 1; - if(msgSize <= UA_MAX_STACKBUF) - stackSize = msgSize; - UA_STACKARRAY(UA_Byte, stackBuf, stackSize); + UA_Byte stackBuf[UA_MAX_STACKBUF]; buf.data = stackBuf; buf.length = msgSize; - UA_StatusCode retval; if(msgSize > UA_MAX_STACKBUF) { - retval = UA_ByteString_allocBuffer(&buf, msgSize); - if(retval != UA_STATUSCODE_GOOD) - return retval; + rv = UA_ByteString_allocBuffer(&buf, msgSize); + UA_CHECK_STATUS(rv, goto cleanup); } - /* Encode the message */ - UA_Byte *bufPos = buf.data; - memset(bufPos, 0, msgSize); - const UA_Byte *bufEnd = &buf.data[buf.length]; - retval = UA_NetworkMessage_encodeBinary(&nm, &bufPos, bufEnd); - if(retval != UA_STATUSCODE_GOOD) { - if(msgSize > UA_MAX_STACKBUF) - UA_ByteString_clear(&buf); - return retval; - } + /* Encode and encrypt the message */ + rv = encodeNetworkMessage(wg, &nm, &buf); + UA_CHECK_STATUS(rv, goto cleanup_with_msg_size); - /* Send the prepared messages */ - retval = connection->channel->send(connection->channel, transportSettings, &buf); - if(msgSize > UA_MAX_STACKBUF) + /* Send out the message */ + rv = connection->channel->send(connection->channel, + &wg->config.transportSettings, &buf); + UA_CHECK_STATUS(rv, goto cleanup_with_msg_size); + +cleanup_with_msg_size: + if(msgSize > UA_MAX_STACKBUF) { UA_ByteString_clear(&buf); - return retval; + } +cleanup: + UA_ByteString_clear(&nm.securityHeader.messageNonce); + UA_free(nm.payload.dataSetPayload.sizes); + return rv; +} + +static void +sendNetworkMessage(UA_Server *server, UA_WriterGroup *wg, UA_PubSubConnection *connection, + UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + switch(wg->config.encodingMimeType) { + case UA_PUBSUB_ENCODING_UADP: + res = sendNetworkMessageBinary(connection, wg, dsm, writerIds, dsmCount); + break; +#ifdef UA_ENABLE_JSON_ENCODING + case UA_PUBSUB_ENCODING_JSON: + res = sendNetworkMessageJson(connection, wg, dsm, writerIds, dsmCount); + break; +#endif + default: + res = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + + /* If sending failed, disable all writer of the writergroup */ + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub Publish: Could not send a NetworkMessage " + "with status code %s", UA_StatusCode_name(res)); + UA_DataSetWriter *dsw; + LIST_FOREACH(dsw, &wg->writers, listEntry) { + UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dsw); + } + return; + } + + /* Increase the sequence number */ + wg->sequenceNumber++; +} + +static void +sendBufferedNetworkMessage(UA_Server *server, UA_WriterGroup *wg, + UA_PubSubConnection *connection) { + UA_NetworkMessageOffsetBuffer *buf = &wg->bufferedMessage; + UA_StatusCode res = UA_NetworkMessage_updateBufferedMessage(buf); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub sending failed - could not update the message"); + UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_ERROR, wg); + return; + } + + res = connection->channel->send(connection->channel, + &wg->config.transportSettings, &buf->buffer); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Publish failed. RT fixed size. sendBufferedNetworkMessage failed"); + UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_ERROR, wg); + return; + } + + /* Sending successful - increase the sequence number */ + wg->sequenceNumber++; } /* This callback triggers the collection and publish of NetworkMessages and the @@ -30023,38 +30225,32 @@ void UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) { UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "Publish Callback"); + // TODO: review if its okay to force correct value from caller side instead + // UA_assert(writerGroup != NULL); + // UA_assert(server != NULL); + if(!writerGroup) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Publish failed. WriterGroup not found"); + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Publish failed. WriterGroup not found"); return; } /* Nothing to do? */ - if(writerGroup->writersCount <= 0) - return; - - /* Binary or Json encoding? */ - if(writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP && - writerGroup->config.encodingMimeType != UA_PUBSUB_ENCODING_JSON) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Publish failed: Unknown encoding type."); + if(writerGroup->writersCount == 0) return; - } /* Find the connection associated with the writer */ UA_PubSubConnection *connection = writerGroup->linkedConnection; if(!connection) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Publish failed. PubSubConnection invalid."); + UA_WriterGroup_setPubSubState(server, UA_PUBSUBSTATE_ERROR, writerGroup); return; } + /* Realtime path - update the buffer message and send directly */ if(writerGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) { - UA_StatusCode res = - sendBufferedNetworkMessage(server, connection, &writerGroup->bufferedMessage, - &writerGroup->config.transportSettings); - if(res == UA_STATUSCODE_GOOD) - writerGroup->sequenceNumber++; + sendBufferedNetworkMessage(server, writerGroup, connection); return; } @@ -30062,110 +30258,107 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) { UA_Byte maxDSM = (UA_Byte)writerGroup->config.maxEncapsulatedDataSetMessageCount; if(writerGroup->config.maxEncapsulatedDataSetMessageCount > UA_BYTE_MAX) maxDSM = UA_BYTE_MAX; - /* If the maxEncapsulatedDataSetMessageCount is set to 0->1 */ + + /* If the maxEncapsulatedDataSetMessageCount is set to 0 -> 1 */ if(maxDSM == 0) maxDSM = 1; /* It is possible to put several DataSetMessages into one NetworkMessage. - * But only if they do not contain promoted fields. NM with only DSM are - * sent out right away. The others are kept in a buffer for "batching". */ + * But only if they do not contain promoted fields. NM with promoted fields + * are sent out right away. The others are kept in a buffer for + * "batching". */ size_t dsmCount = 0; - UA_DataSetWriter *dsw; UA_STACKARRAY(UA_UInt16, dsWriterIds, writerGroup->writersCount); UA_STACKARRAY(UA_DataSetMessage, dsmStore, writerGroup->writersCount); + + UA_DataSetWriter *dsw; LIST_FOREACH(dsw, &writerGroup->writers, listEntry) { + if(dsw->state != UA_PUBSUBSTATE_OPERATIONAL) + continue; + /* Find the dataset */ UA_PublishedDataSet *pds = UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet); if(!pds) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub Publish: PublishedDataSet not found"); + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub Publish: PublishedDataSet not found"); + UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dsw); continue; } /* Generate the DSM */ + dsWriterIds[dsmCount] = dsw->config.dataSetWriterId; UA_StatusCode res = UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw); if(res != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub Publish: DataSetMessage creation failed"); + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub Publish: DataSetMessage creation failed"); + UA_DataSetWriter_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dsw); continue; } - /* Send right away if there is only this DSM in a NM. If promoted fields - * are contained in the PublishedDataSet, then this DSM must go into a - * dedicated NM as well. */ - if(pds->promotedFieldsCount > 0 || maxDSM == 1) { - if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP){ - res = sendNetworkMessage(connection, writerGroup, &dsmStore[dsmCount], - &dsw->config.dataSetWriterId, 1, - &writerGroup->config.messageSettings, - &writerGroup->config.transportSettings); - } else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) { - res = sendNetworkMessageJson(connection, &dsmStore[dsmCount], - &dsw->config.dataSetWriterId, 1, - &writerGroup->config.transportSettings); - } - - if(res != UA_STATUSCODE_GOOD) - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub Publish: Could not send a NetworkMessage"); + /* There is no promoted field -> send right away */ + if(pds->promotedFieldsCount > 0) { + sendNetworkMessage(server, writerGroup, connection, &dsmStore[dsmCount], + &dsWriterIds[dsmCount], 1); + /* Clean up the current store entry */ if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS) { for(size_t i = 0; i < dsmStore[dsmCount].data.keyFrameData.fieldCount; ++i) { dsmStore[dsmCount].data.keyFrameData.dataSetFields[i].value.data = NULL; } } + UA_DataSetMessage_clear(&dsmStore[dsmCount]); - UA_DataSetMessage_free(&dsmStore[dsmCount]); - continue; + continue; /* Don't increase the dsmCount, reuse the slot */ } - dsWriterIds[dsmCount] = dsw->config.dataSetWriterId; dsmCount++; } /* Send the NetworkMessages with batched DataSetMessages */ - size_t nmCount = (dsmCount / maxDSM) + ((dsmCount % maxDSM) == 0 ? 0 : 1); - for(UA_UInt32 i = 0; i < nmCount; i++) { - UA_Byte nmDsmCount = maxDSM; - if(i == nmCount - 1 && (dsmCount % maxDSM)) - nmDsmCount = (UA_Byte)dsmCount % maxDSM; - UA_StatusCode res3 = UA_STATUSCODE_GOOD; - if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP){ - res3 = sendNetworkMessage(connection, writerGroup, &dsmStore[i * maxDSM], - &dsWriterIds[i * maxDSM], nmDsmCount, - &writerGroup->config.messageSettings, - &writerGroup->config.transportSettings); - } else if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON){ - res3 = sendNetworkMessageJson(connection, &dsmStore[i * maxDSM], - &dsWriterIds[i * maxDSM], nmDsmCount, - &writerGroup->config.transportSettings); - } - - if(res3 != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PubSub Publish: Sending a NetworkMessage failed"); - continue; - } + UA_Byte nmDsmCount = 0; + for(size_t i = 0; i < dsmCount; i += nmDsmCount) { + /* How many dsm are batched in this iteration? */ + nmDsmCount = (i + maxDSM > dsmCount) ? (UA_Byte)(dsmCount - i) : maxDSM; - writerGroup->sequenceNumber++; + /* Send the batched messages */ + sendNetworkMessage(server, writerGroup, connection, &dsmStore[i], + &dsWriterIds[i], nmDsmCount); } /* Clean up DSM */ - for(size_t i = 0; i < dsmCount; i++) - UA_DataSetMessage_free(&dsmStore[i]); + for(size_t i = 0; i < dsmCount; i++) { + if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS) { + for(size_t j = 0; j < dsmStore[i].data.keyFrameData.fieldCount; ++j) { + dsmStore[i].data.keyFrameData.dataSetFields[j].value.data = NULL; + } + } + UA_DataSetMessage_clear(&dsmStore[i]); + } } /* Add new publishCallback. The first execution is triggered directly after * creation. */ UA_StatusCode UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup) { - UA_StatusCode retval = - UA_PubSubManager_addRepeatedCallback(server, - (UA_ServerCallback) UA_WriterGroup_publishCallback, - writerGroup, writerGroup->config.publishingInterval, - &writerGroup->publishCallbackId); + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(writerGroup->config.pubsubManagerCallback.addCustomCallback) + retval |= writerGroup->config.pubsubManagerCallback. + addCustomCallback(server, writerGroup->identifier, + (UA_ServerCallback) UA_WriterGroup_publishCallback, + writerGroup, writerGroup->config.publishingInterval, + NULL, // TODO: Send base time from writer group config + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, // TODO: Send timer policy from writer group config + &writerGroup->publishCallbackId); + else + retval |= UA_PubSubManager_addRepeatedCallback(server, + (UA_ServerCallback) UA_WriterGroup_publishCallback, + writerGroup, writerGroup->config.publishingInterval, + NULL, // TODO: Send base time from writer group config + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, // TODO: Send timer policy from writer group config + &writerGroup->publishCallbackId); + if(retval == UA_STATUSCODE_GOOD) writerGroup->publishCallbackIsRegistered = true; @@ -30176,7 +30369,7 @@ UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup #endif /* UA_ENABLE_PUBSUB */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_reader.c" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_reader.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -30185,9 +30378,11 @@ UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner) * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes) */ + #ifdef UA_ENABLE_PUBSUB /* conditional compilation */ @@ -30197,401 +30392,562 @@ UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup #ifdef UA_ENABLE_PUBSUB_DELTAFRAMES #endif -#define UA_MAX_SIZENAME 64 /* Max size of Qualified Name of Subscribed Variable */ +#ifdef UA_ENABLE_PUBSUB_BUFMALLOC +#endif -/***************/ -/* ReaderGroup */ -/***************/ +/* This functionality of this API will be used in future to create mirror Variables - TODO */ +/* #define UA_MAX_SIZENAME 64 */ /* Max size of Qualified Name of Subscribed Variable */ -UA_StatusCode -UA_Server_addReaderGroup(UA_Server *server, UA_NodeId connectionIdentifier, - const UA_ReaderGroupConfig *readerGroupConfig, - UA_NodeId *readerGroupIdentifier) { - UA_StatusCode retval = UA_STATUSCODE_GOOD; +/* Clear DataSetReader */ +static void +UA_DataSetReader_clear(UA_Server *server, UA_DataSetReader *dataSetReader); - /* Check for valid readergroup configuration */ - if(!readerGroupConfig) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +static void +UA_PubSubDSRDataSetField_sampleValue(UA_Server *server, UA_DataSetReader *dataSetReader, + UA_DataValue *value, UA_FieldTargetVariable *ftv) { + /* TODO: Static value source without RT information model + * This API supports only to external datasource in RT configutation + * TODO: Extend to support other configuration if required */ + + /* Get the Node */ + const UA_VariableNode *rtNode = (const UA_VariableNode *) + UA_NODESTORE_GET(server, &ftv->targetVariable.targetNodeId); + if(!rtNode) + return; - /* Search the connection by the given connectionIdentifier */ - UA_PubSubConnection *currentConnectionContext = - UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier); - if(!currentConnectionContext) { - return UA_STATUSCODE_BADNOTFOUND; + if(rtNode->valueBackend.backendType == UA_VALUEBACKENDTYPE_EXTERNAL) { + /* Set the external source in the dataset reader config */ + ftv->externalDataValue = rtNode->valueBackend.backend.external.value; + + /* Get the value to compute the offsets */ + *value = **rtNode->valueBackend.backend.external.value; + value->value.storageType = UA_VARIANT_DATA_NODELETE; } - /* Allocate memory for new reader group */ - UA_ReaderGroup *newGroup = (UA_ReaderGroup *)UA_calloc(1, sizeof(UA_ReaderGroup)); - if(!newGroup) { + UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode); +} + +static UA_StatusCode +UA_PubSubDataSetReader_generateKeyFrameMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, + UA_DataSetReader *dataSetReader) { + /* Prepare DataSetMessageContent */ + UA_TargetVariables *tv = &dataSetReader->config.subscribedDataSet.subscribedDataSetTarget; + dataSetMessage->header.dataSetMessageValid = true; + dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME; + dataSetMessage->data.keyFrameData.fieldCount = (UA_UInt16) tv->targetVariablesSize; + dataSetMessage->data.keyFrameData.dataSetFields = (UA_DataValue *) + UA_Array_new(tv->targetVariablesSize, &UA_TYPES[UA_TYPES_DATAVALUE]); + if(!dataSetMessage->data.keyFrameData.dataSetFields) return UA_STATUSCODE_BADOUTOFMEMORY; - } - /* Generate nodeid for the readergroup identifier */ - newGroup->linkedConnection = currentConnectionContext->identifier; - UA_PubSubManager_generateUniqueNodeId(server, &newGroup->identifier); - if(readerGroupIdentifier) { - UA_NodeId_copy(&newGroup->identifier, readerGroupIdentifier); - } + for(size_t counter = 0; counter < tv->targetVariablesSize; counter++) { + /* Sample the value and set the source in the reader config */ + UA_DataValue *dfv = &dataSetMessage->data.keyFrameData.dataSetFields[counter]; + UA_FieldTargetVariable *ftv = &tv->targetVariables[counter]; + UA_PubSubDSRDataSetField_sampleValue(server, dataSetReader, dfv, ftv); - /* Deep copy of the config */ - retval |= UA_ReaderGroupConfig_copy(readerGroupConfig, &newGroup->config); - retval |= UA_ReaderGroup_addSubscribeCallback(server, newGroup); - LIST_INSERT_HEAD(¤tConnectionContext->readerGroups, newGroup, listEntry); - currentConnectionContext->readerGroupsSize++; + /* Deactivate statuscode? */ + if(((u64)dataSetReader->config.dataSetFieldContentMask & + (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0) + dfv->hasStatus = false; -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - addReaderGroupRepresentation(server, newGroup); -#endif + /* Deactivate timestamps */ + if(((u64)dataSetReader->config.dataSetFieldContentMask & + (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0) + dfv->hasSourceTimestamp = false; + if(((u64)dataSetReader->config.dataSetFieldContentMask & + (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0) + dfv->hasSourcePicoseconds = false; + if(((u64)dataSetReader->config.dataSetFieldContentMask & + (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0) + dfv->hasServerTimestamp = false; + if(((u64)dataSetReader->config.dataSetFieldContentMask & + (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0) + dfv->hasServerPicoseconds = false; + } - return retval; + return UA_STATUSCODE_GOOD; } +/* Generate a DataSetMessage for the given reader. */ UA_StatusCode -UA_Server_removeReaderGroup(UA_Server *server, UA_NodeId groupIdentifier) { - UA_ReaderGroup* readerGroup = UA_ReaderGroup_findRGbyId(server, groupIdentifier); - if(readerGroup == NULL) { - return UA_STATUSCODE_BADNOTFOUND; +UA_DataSetReader_generateDataSetMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, + UA_DataSetReader *dataSetReader) { + /* Reset the message */ + memset(dataSetMessage, 0, sizeof(UA_DataSetMessage)); + + /* Support only for UADP configuration + * TODO: JSON encoding if UA_DataSetReader_generateDataSetMessage used other + * that RT configuration */ + + UA_ExtensionObject *settings = &dataSetReader->config.messageSettings; + if(settings->content.decoded.type != &UA_TYPES[UA_TYPES_UADPDATASETREADERMESSAGEDATATYPE]) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Only UADP encoding is supported."); + return UA_STATUSCODE_BADNOTSUPPORTED; } - /* Search the connection to which the given readergroup is connected to */ - UA_PubSubConnection *connection = - UA_PubSubConnection_findConnectionbyId(server, readerGroup->linkedConnection); - if(connection == NULL) { - return UA_STATUSCODE_BADNOTFOUND; + /* The configuration Flags are included inside the std. defined UA_UadpDataSetReaderMessageDataType */ + UA_UadpDataSetReaderMessageDataType defaultUadpConfiguration; + UA_UadpDataSetReaderMessageDataType *dataSetReaderMessageDataType = + (UA_UadpDataSetReaderMessageDataType*) settings->content.decoded.data; + + if(!(settings->encoding == UA_EXTENSIONOBJECT_DECODED || + settings->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) || + !dataSetReaderMessageDataType->dataSetMessageContentMask) { + /* create default flag configuration if no dataSetMessageContentMask or even messageSettings in + * UadpDataSetWriterMessageDataType was passed in */ + memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetReaderMessageDataType)); + defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask) + ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP | + (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION | + (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION); + dataSetReaderMessageDataType = &defaultUadpConfiguration; } - /* Unregister subscribe callback */ - UA_PubSubManager_removeRepeatedPubSubCallback(server, readerGroup->subscribeCallbackId); -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - /* To Do:RemoveGroupRepresentation(server, &readerGroup->identifier) */ -#endif + /* Sanity-test the configuration */ + if(dataSetReaderMessageDataType && + (dataSetReaderMessageDataType->networkMessageNumber != 0 || + dataSetReaderMessageDataType->dataSetOffset != 0)) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Static DSM configuration not supported. Using defaults"); + dataSetReaderMessageDataType->networkMessageNumber = 0; + dataSetReaderMessageDataType->dataSetOffset = 0; + } - /* UA_Server_ReaderGroup_delete also removes itself from the list */ - UA_Server_ReaderGroup_delete(server, readerGroup); - /* Remove readerGroup from Connection */ - LIST_REMOVE(readerGroup, listEntry); - UA_free(readerGroup); - return UA_STATUSCODE_GOOD; -} + /* The field encoding depends on the flags inside the reader config. */ + if(dataSetReader->config.dataSetFieldContentMask & + (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA) { + dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_RAWDATA; + } else if((u64)dataSetReader->config.dataSetFieldContentMask & + ((u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP | + (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS | + (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS | + (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE)) { + dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE; + } else { + dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT; + } -/* TODO: Implement -UA_StatusCode -UA_Server_ReaderGroup_updateConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, - const UA_ReaderGroupConfig *config) { - return UA_STATUSCODE_BADNOTIMPLEMENTED; -} -*/ + /* Std: 'The DataSetMessageContentMask defines the flags for the content + * of the DataSetMessage header.' */ + if((u64)dataSetReaderMessageDataType->dataSetMessageContentMask & + (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) { + dataSetMessage->header.configVersionMajorVersionEnabled = true; + dataSetMessage->header.configVersionMajorVersion = + dataSetReader->config.dataSetMetaData.configurationVersion.majorVersion; + } -UA_StatusCode -UA_Server_ReaderGroup_getConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, - UA_ReaderGroupConfig *config) { - if(!config) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + if((u64)dataSetReaderMessageDataType->dataSetMessageContentMask & + (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) { + dataSetMessage->header.configVersionMinorVersionEnabled = true; + dataSetMessage->header.configVersionMinorVersion = + dataSetReader->config.dataSetMetaData.configurationVersion.minorVersion; } - /* Identify the readergroup through the readerGroupIdentifier */ - UA_ReaderGroup *currentReaderGroup = UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier); - if(!currentReaderGroup) { - return UA_STATUSCODE_BADNOTFOUND; + if((u64)dataSetReaderMessageDataType->dataSetMessageContentMask & + (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) { + /* Will be modified when subscriber receives new nw msg */ + dataSetMessage->header.dataSetMessageSequenceNrEnabled = true; + dataSetMessage->header.dataSetMessageSequenceNr = 1; } - UA_ReaderGroupConfig tmpReaderGroupConfig; - /* deep copy of the actual config */ - UA_ReaderGroupConfig_copy(¤tReaderGroup->config, &tmpReaderGroupConfig); - *config = tmpReaderGroupConfig; - return UA_STATUSCODE_GOOD; -} + if((u64)dataSetReaderMessageDataType->dataSetMessageContentMask & + (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) { + dataSetMessage->header.timestampEnabled = true; + dataSetMessage->header.timestamp = UA_DateTime_now(); + } -void -UA_Server_ReaderGroup_delete(UA_Server* server, UA_ReaderGroup *readerGroup) { - /* To Do Call UA_ReaderGroupConfig_delete */ - UA_DataSetReader *dataSetReader, *tmpDataSetReader; - LIST_FOREACH_SAFE(dataSetReader, &readerGroup->readers, listEntry, tmpDataSetReader) { - UA_DataSetReader_delete(server, dataSetReader); + /* TODO: Picoseconds resolution not supported atm */ + if((u64)dataSetReaderMessageDataType->dataSetMessageContentMask & + (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) { + dataSetMessage->header.picoSecondsIncluded = false; } - UA_PubSubConnection* pConn = - UA_PubSubConnection_findConnectionbyId(server, readerGroup->linkedConnection); - if(pConn != NULL) { - pConn->readerGroupsSize--; + + if((u64)dataSetReaderMessageDataType->dataSetMessageContentMask & + (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS) { + dataSetMessage->header.statusEnabled = true; } - /* Delete ReaderGroup and its members */ - UA_String_deleteMembers(&readerGroup->config.name); - UA_NodeId_deleteMembers(&readerGroup->linkedConnection); - UA_NodeId_deleteMembers(&readerGroup->identifier); + /* Not supported for Delta frames atm */ + return UA_PubSubDataSetReader_generateKeyFrameMessage(server, dataSetMessage, dataSetReader); } UA_StatusCode -UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src, - UA_ReaderGroupConfig *dst) { - /* Currently simple memcpy only */ - memcpy(&dst->securityParameters, &src->securityParameters, sizeof(UA_PubSubSecurityParameters)); - UA_String_copy(&src->name, &dst->name); - return UA_STATUSCODE_GOOD; -} +UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection, + UA_DataSetReader *dataSetReader, + UA_DataSetMessage *dsm, UA_UInt16 *writerId, + UA_Byte dsmCount, UA_NetworkMessage *nm) { + UA_ExtensionObject *settings = &dataSetReader->config.messageSettings; + if(settings->content.decoded.type != &UA_TYPES[UA_TYPES_UADPDATASETREADERMESSAGEDATATYPE]) + return UA_STATUSCODE_BADNOTSUPPORTED; -static UA_StatusCode -checkReaderIdentifier(UA_Server *server, UA_NetworkMessage *pMsg, UA_DataSetReader *reader) { - if(!pMsg->groupHeaderEnabled && - !pMsg->groupHeader.writerGroupIdEnabled && - !pMsg->payloadHeaderEnabled) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Cannot process DataSetReader without WriterGroup" - "and DataSetWriter identifiers"); - return UA_STATUSCODE_BADNOTIMPLEMENTED; - } + UA_UadpDataSetReaderMessageDataType *dsrm = + (UA_UadpDataSetReaderMessageDataType*)settings->content.decoded.data; + nm->publisherIdEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID) != 0; + nm->groupHeaderEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER) != 0; + nm->groupHeader.writerGroupIdEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID) != 0; + nm->groupHeader.groupVersionEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPVERSION) != 0; + nm->groupHeader.networkMessageNumberEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_NETWORKMESSAGENUMBER) != 0; + nm->groupHeader.sequenceNumberEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_SEQUENCENUMBER) != 0; + nm->payloadHeaderEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER) != 0; + nm->timestampEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_TIMESTAMP) != 0; + nm->picosecondsEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PICOSECONDS) != 0; + nm->dataSetClassIdEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_DATASETCLASSID) != 0; + nm->promotedFieldsEnabled = ((u64)dsrm->networkMessageContentMask & + (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PROMOTEDFIELDS) != 0; + nm->version = 1; + nm->networkMessageType = UA_NETWORKMESSAGE_DATASET; + + if(!UA_DataType_isNumeric(dataSetReader->config.publisherId.type)) + return UA_STATUSCODE_BADNOTSUPPORTED; - if((reader->config.writerGroupId == pMsg->groupHeader.writerGroupId) && - (reader->config.dataSetWriterId == *pMsg->payloadHeader.dataSetPayloadHeader.dataSetWriterIds)) { - UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, - "DataSetReader found. Process NetworkMessage"); - return UA_STATUSCODE_GOOD; + switch(dataSetReader->config.publisherId.type->typeKind) { + case UA_DATATYPEKIND_BYTE: + nm->publisherIdType = UA_PUBLISHERDATATYPE_BYTE; + nm->publisherId.publisherIdByte = *(UA_Byte *) dataSetReader->config.publisherId.data; + break; + case UA_DATATYPEKIND_UINT16: + nm->publisherIdType = UA_PUBLISHERDATATYPE_UINT16; + nm->publisherId.publisherIdUInt16 = *(UA_UInt16 *) dataSetReader->config.publisherId.data; + break; + case UA_DATATYPEKIND_UINT32: + nm->publisherIdType = UA_PUBLISHERDATATYPE_UINT32; + nm->publisherId.publisherIdUInt32 = *(UA_UInt32 *) dataSetReader->config.publisherId.data; + break; + case UA_DATATYPEKIND_UINT64: + nm->publisherIdType = UA_PUBLISHERDATATYPE_UINT64; + nm->publisherId.publisherIdUInt64 = *(UA_UInt64 *) dataSetReader->config.publisherId.data; + break; + default: + return UA_STATUSCODE_BADNOTSUPPORTED; } - return UA_STATUSCODE_BADNOTFOUND; -} + if(nm->groupHeader.sequenceNumberEnabled) + nm->groupHeader.sequenceNumber = 1; /* Will be modified when subscriber receives new nw msg. */ -static UA_StatusCode -getReaderFromIdentifier(UA_Server *server, UA_NetworkMessage *pMsg, - UA_DataSetReader **dataSetReader, UA_PubSubConnection *pConnection) { - UA_StatusCode retval = UA_STATUSCODE_BADNOTFOUND; - if(!pMsg->publisherIdEnabled) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Cannot process DataSetReader without PublisherId"); - return UA_STATUSCODE_BADNOTIMPLEMENTED; /* TODO: Handle DSR without PublisherId */ - } + if(nm->groupHeader.groupVersionEnabled) + nm->groupHeader.groupVersion = dsrm->groupVersion; - UA_ReaderGroup* readerGroup; - LIST_FOREACH(readerGroup, &pConnection->readerGroups, listEntry) { - UA_DataSetReader *tmpReader; - LIST_FOREACH(tmpReader, &readerGroup->readers, listEntry) { - switch (pMsg->publisherIdType) { - case UA_PUBLISHERDATATYPE_BYTE: - if(tmpReader->config.publisherId.type == &UA_TYPES[UA_TYPES_BYTE] && - pMsg->publisherIdType == UA_PUBLISHERDATATYPE_BYTE && - pMsg->publisherId.publisherIdByte == *(UA_Byte*)tmpReader->config.publisherId.data) { - retval = checkReaderIdentifier(server, pMsg, tmpReader); - } - break; - case UA_PUBLISHERDATATYPE_UINT16: - if(tmpReader->config.publisherId.type == &UA_TYPES[UA_TYPES_UINT16] && - pMsg->publisherIdType == UA_PUBLISHERDATATYPE_UINT16 && - pMsg->publisherId.publisherIdUInt16 == *(UA_UInt16*) tmpReader->config.publisherId.data) { - retval = checkReaderIdentifier(server, pMsg, tmpReader); - } + /* Compute the length of the dsm separately for the header */ + UA_UInt16 *dsmLengths = (UA_UInt16 *) UA_calloc(dsmCount, sizeof(UA_UInt16)); + if(!dsmLengths) + return UA_STATUSCODE_BADOUTOFMEMORY; + for(UA_Byte i = 0; i < dsmCount; i++){ + dsmLengths[i] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsm[i], NULL, 0); + switch(dataSetReader->config.expectedEncoding) { + case UA_PUBSUB_RT_UNKNOWN: break; - case UA_PUBLISHERDATATYPE_UINT32: - if(tmpReader->config.publisherId.type == &UA_TYPES[UA_TYPES_UINT32] && - pMsg->publisherIdType == UA_PUBLISHERDATATYPE_UINT32 && - pMsg->publisherId.publisherIdUInt32 == *(UA_UInt32*)tmpReader->config.publisherId.data) { - retval = checkReaderIdentifier(server, pMsg, tmpReader); - } + case UA_PUBSUB_RT_VARIANT: + dsm[i].header.fieldEncoding = UA_FIELDENCODING_VARIANT; break; - case UA_PUBLISHERDATATYPE_UINT64: - if(tmpReader->config.publisherId.type == &UA_TYPES[UA_TYPES_UINT64] && - pMsg->publisherIdType == UA_PUBLISHERDATATYPE_UINT64 && - pMsg->publisherId.publisherIdUInt64 == *(UA_UInt64*)tmpReader->config.publisherId.data) { - retval = checkReaderIdentifier(server, pMsg, tmpReader); - } + case UA_PUBSUB_RT_DATA_VALUE: + dsm[i].header.fieldEncoding = UA_FIELDENCODING_DATAVALUE; break; - case UA_PUBLISHERDATATYPE_STRING: - if(tmpReader->config.publisherId.type == &UA_TYPES[UA_TYPES_STRING] && - pMsg->publisherIdType == UA_PUBLISHERDATATYPE_STRING && - UA_String_equal(&pMsg->publisherId.publisherIdString, - (UA_String*)tmpReader->config.publisherId.data)) { - retval = checkReaderIdentifier(server, pMsg, tmpReader); - } + case UA_PUBSUB_RT_RAW: + dsm[i].header.fieldEncoding = UA_FIELDENCODING_RAWDATA; break; - default: - return UA_STATUSCODE_BADINTERNALERROR; - } - - if(retval == UA_STATUSCODE_GOOD) { - *dataSetReader = tmpReader; - return UA_STATUSCODE_GOOD; - } } } - - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Dataset reader not found. Check PublisherID, WriterGroupID and DatasetWriterID"); - return UA_STATUSCODE_BADNOTFOUND; -} - -UA_ReaderGroup * -UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier) { - UA_PubSubConnection *pubSubConnection; - TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){ - UA_ReaderGroup* readerGroup = NULL; - LIST_FOREACH(readerGroup, &pubSubConnection->readerGroups, listEntry) { - if(UA_NodeId_equal(&identifier, &readerGroup->identifier)) { - return readerGroup; - } - - } - } - return NULL; -} - -UA_DataSetReader *UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier) { - UA_PubSubConnection *pubSubConnection; - TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){ - UA_ReaderGroup* readerGroup = NULL; - LIST_FOREACH(readerGroup, &pubSubConnection->readerGroups, listEntry) { - UA_DataSetReader *tmpReader; - LIST_FOREACH(tmpReader, &readerGroup->readers, listEntry) { - if(UA_NodeId_equal(&tmpReader->identifier, &identifier)) { - return tmpReader; - } - } - } - } - return NULL; + nm->payloadHeader.dataSetPayloadHeader.count = dsmCount; + nm->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerId; + nm->groupHeader.writerGroupId = dataSetReader->config.writerGroupId; + nm->groupHeader.networkMessageNumber = 1; /* number of the NetworkMessage inside a PublishingInterval */ + nm->payload.dataSetPayload.sizes = dsmLengths; + nm->payload.dataSetPayload.dataSetMessages = dsm; + return UA_STATUSCODE_GOOD; } -/* This callback triggers the collection and reception of NetworkMessages and the - * contained DataSetMessages. */ -void UA_ReaderGroup_subscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup) { - UA_PubSubConnection *connection = - UA_PubSubConnection_findConnectionbyId(server, readerGroup->linkedConnection); - UA_ByteString buffer; - if(UA_ByteString_allocBuffer(&buffer, 512) != UA_STATUSCODE_GOOD) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, "Message buffer alloc failed!"); - return; +static UA_StatusCode +checkReaderIdentifier(UA_Server *server, UA_NetworkMessage *msg, + UA_DataSetReader *reader) { + if(!msg->groupHeaderEnabled || !msg->groupHeader.writerGroupIdEnabled || + !msg->payloadHeaderEnabled) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Cannot process DataSetReader without WriterGroup" + "and DataSetWriter identifiers"); + return UA_STATUSCODE_BADNOTIMPLEMENTED; } - connection->channel->receive(connection->channel, &buffer, NULL, 1000); - if(buffer.length > 0) { - UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Message received:"); - UA_NetworkMessage currentNetworkMessage; - memset(¤tNetworkMessage, 0, sizeof(UA_NetworkMessage)); - size_t currentPosition = 0; - UA_NetworkMessage_decodeBinary(&buffer, ¤tPosition, ¤tNetworkMessage); - UA_Server_processNetworkMessage(server, ¤tNetworkMessage, connection); - UA_NetworkMessage_deleteMembers(¤tNetworkMessage); + switch(msg->publisherIdType) { + case UA_PUBLISHERDATATYPE_BYTE: + if(reader->config.publisherId.type == &UA_TYPES[UA_TYPES_BYTE] && + msg->publisherIdType == UA_PUBLISHERDATATYPE_BYTE && + msg->publisherId.publisherIdByte == *(UA_Byte*)reader->config.publisherId.data) + break; + return UA_STATUSCODE_BADNOTFOUND; + case UA_PUBLISHERDATATYPE_UINT16: + if(reader->config.publisherId.type == &UA_TYPES[UA_TYPES_UINT16] && + msg->publisherIdType == UA_PUBLISHERDATATYPE_UINT16 && + msg->publisherId.publisherIdUInt16 == *(UA_UInt16*)reader->config.publisherId.data) + break; + return UA_STATUSCODE_BADNOTFOUND; + case UA_PUBLISHERDATATYPE_UINT32: + if(reader->config.publisherId.type == &UA_TYPES[UA_TYPES_UINT32] && + msg->publisherIdType == UA_PUBLISHERDATATYPE_UINT32 && + msg->publisherId.publisherIdUInt32 == *(UA_UInt32*)reader->config.publisherId.data) + break; + return UA_STATUSCODE_BADNOTFOUND; + case UA_PUBLISHERDATATYPE_UINT64: + if(reader->config.publisherId.type == &UA_TYPES[UA_TYPES_UINT64] && + msg->publisherIdType == UA_PUBLISHERDATATYPE_UINT64 && + msg->publisherId.publisherIdUInt64 == *(UA_UInt64*)reader->config.publisherId.data) + break; + return UA_STATUSCODE_BADNOTFOUND; + case UA_PUBLISHERDATATYPE_STRING: + if(reader->config.publisherId.type == &UA_TYPES[UA_TYPES_STRING] && + msg->publisherIdType == UA_PUBLISHERDATATYPE_STRING && + UA_String_equal(&msg->publisherId.publisherIdString, + (UA_String*)reader->config.publisherId.data)) + break; + return UA_STATUSCODE_BADNOTFOUND; + default: + return UA_STATUSCODE_BADNOTFOUND; } - UA_ByteString_deleteMembers(&buffer); -} - -/* Add new subscribeCallback. The first execution is triggered directly after - * creation. */ -UA_StatusCode -UA_ReaderGroup_addSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup) { - UA_StatusCode retval = UA_STATUSCODE_GOOD; - retval |= UA_PubSubManager_addRepeatedCallback(server, - (UA_ServerCallback) UA_ReaderGroup_subscribeCallback, - readerGroup, 5, &readerGroup->subscribeCallbackId); - - if(retval == UA_STATUSCODE_GOOD) { - readerGroup->subscribeCallbackIsRegistered = true; + if(reader->config.writerGroupId == msg->groupHeader.writerGroupId && + reader->config.dataSetWriterId == *msg->payloadHeader.dataSetPayloadHeader.dataSetWriterIds) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "DataSetReader found. Process NetworkMessage"); + return UA_STATUSCODE_GOOD; } - /* Run once after creation */ - UA_ReaderGroup_subscribeCallback(server, readerGroup); - return retval; + return UA_STATUSCODE_BADNOTFOUND; } -/**********/ -/* Reader */ -/**********/ - UA_StatusCode UA_Server_addDataSetReader(UA_Server *server, UA_NodeId readerGroupIdentifier, - const UA_DataSetReaderConfig *dataSetReaderConfig, - UA_NodeId *readerIdentifier) { + const UA_DataSetReaderConfig *dataSetReaderConfig, + UA_NodeId *readerIdentifier) { /* Search the reader group by the given readerGroupIdentifier */ UA_ReaderGroup *readerGroup = UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier); - - if(!dataSetReaderConfig) { + if(readerGroup == NULL) return UA_STATUSCODE_BADNOTFOUND; - } - if(readerGroup == NULL) { + if(!dataSetReaderConfig) return UA_STATUSCODE_BADNOTFOUND; + + if(readerGroup->configurationFrozen){ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Add DataSetReader failed. Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; } /* Allocate memory for new DataSetReader */ - UA_DataSetReader *newDataSetReader = (UA_DataSetReader *)UA_calloc(1, sizeof(UA_DataSetReader)); + UA_DataSetReader *newDataSetReader = (UA_DataSetReader *) + UA_calloc(1, sizeof(UA_DataSetReader)); + if(!newDataSetReader) + return UA_STATUSCODE_BADOUTOFMEMORY; + + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + newDataSetReader->componentType = UA_PUBSUB_COMPONENT_DATASETREADER; + if(readerGroup->state == UA_PUBSUBSTATE_OPERATIONAL) { + retVal = UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, newDataSetReader); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Add DataSetReader failed. setPubSubState failed."); + UA_free(newDataSetReader); + newDataSetReader = 0; + return retVal; + } + } + /* Copy the config into the new dataSetReader */ UA_DataSetReaderConfig_copy(dataSetReaderConfig, &newDataSetReader->config); newDataSetReader->linkedReaderGroup = readerGroup->identifier; - UA_PubSubManager_generateUniqueNodeId(server, &newDataSetReader->identifier); - if(readerIdentifier != NULL) { - UA_NodeId_copy(&newDataSetReader->identifier, readerIdentifier); + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + retVal = addDataSetReaderRepresentation(server, newDataSetReader); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Add DataSetReader failed. addDataSetReaderRepresentation failed."); + UA_DataSetReaderConfig_clear(&newDataSetReader->config); + UA_free(newDataSetReader); + newDataSetReader = 0; + return retVal; } +#else + UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, + &newDataSetReader->identifier); +#endif + +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* create message receive timeout timer */ + retVal = server->config.pubSubConfig.monitoringInterface.createMonitoring( + server, + newDataSetReader->identifier, + UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, + newDataSetReader, + UA_DataSetReader_handleMessageReceiveTimeout); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Add DataSetReader failed. Create message receive timeout timer failed."); + UA_DataSetReaderConfig_clear(&newDataSetReader->config); + UA_free(newDataSetReader); + newDataSetReader = 0; + return retVal; + } +#endif /* UA_ENABLE_PUBSUB_MONITORING */ /* Add the new reader to the group */ LIST_INSERT_HEAD(&readerGroup->readers, newDataSetReader, listEntry); readerGroup->readersCount++; -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - addDataSetReaderRepresentation(server, newDataSetReader); -#endif + if(readerIdentifier) + UA_NodeId_copy(&newDataSetReader->identifier, readerIdentifier); - return UA_STATUSCODE_GOOD; + return retVal; } UA_StatusCode UA_Server_removeDataSetReader(UA_Server *server, UA_NodeId readerIdentifier) { /* Remove datasetreader given by the identifier */ - UA_DataSetReader *dataSetReader = UA_ReaderGroup_findDSRbyId(server, readerIdentifier); - if(!dataSetReader) { + UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, readerIdentifier); + if(!dsr) return UA_STATUSCODE_BADNOTFOUND; + + if(dsr->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Remove DataSetReader failed. " + "Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - removeDataSetReaderRepresentation(server, dataSetReader); + removeDataSetReaderRepresentation(server, dsr); #endif - UA_DataSetReader_delete(server, dataSetReader); - return UA_STATUSCODE_GOOD; + UA_StatusCode res = UA_STATUSCODE_GOOD; +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* Stop and remove message receive timeout timer */ + if(dsr->msgRcvTimeoutTimerRunning) { + res = server->config.pubSubConfig.monitoringInterface. + stopMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Remove DataSetReader failed. Stop message " + "receive timeout timer of DataSetReader '%.*s' failed.", + (int) dsr->config.name.length, dsr->config.name.data); + } + } + + res |= server->config.pubSubConfig.monitoringInterface. + deleteMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Remove DataSetReader failed. Delete message receive " + "timeout timer of DataSetReader '%.*s' failed.", + (int) dsr->config.name.length, dsr->config.name.data); + } +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + + UA_DataSetReader_clear(server, dsr); + return res; } UA_StatusCode UA_Server_DataSetReader_updateConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier, UA_NodeId readerGroupIdentifier, const UA_DataSetReaderConfig *config) { - if(config == NULL) { + if(config == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; - } UA_DataSetReader *currentDataSetReader = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier); + if(!currentDataSetReader) + return UA_STATUSCODE_BADNOTFOUND; + + if(currentDataSetReader->configurationFrozen){ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Update DataSetReader config failed. " + "Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + UA_ReaderGroup *currentReaderGroup = UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier); - if(!currentDataSetReader) { - return UA_STATUSCODE_BADNOTFOUND; + if(currentReaderGroup->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Update DataSetReader config failed. " + "Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; } /* The update functionality will be extended during the next PubSub batches. - * Currently is only a change of the publishing interval possible. */ - if(currentDataSetReader->config.writerGroupId != config->writerGroupId) { - UA_PubSubManager_removeRepeatedPubSubCallback(server, currentReaderGroup->subscribeCallbackId); - currentDataSetReader->config.writerGroupId = config->writerGroupId; - UA_ReaderGroup_subscribeCallback(server, currentReaderGroup); - } - else { + * Currently changes for writerGroupId, dataSetWriterId and TargetVariables are possible. */ + if(currentDataSetReader->config.writerGroupId != config->writerGroupId) + currentDataSetReader->config.writerGroupId = config->writerGroupId; + + if(currentDataSetReader->config.dataSetWriterId != config->dataSetWriterId) + currentDataSetReader->config.dataSetWriterId = config->dataSetWriterId; + + if(currentDataSetReader->config.subscribedDataSetType != UA_PUBSUB_SDS_TARGET) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "No or unsupported ReaderGroup update."); + "Unsupported SubscribedDataSetType."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; } - return UA_STATUSCODE_GOOD; + UA_TargetVariables *oldTV = + ¤tDataSetReader->config.subscribedDataSet.subscribedDataSetTarget; + const UA_TargetVariables *newTV = + &config->subscribedDataSet.subscribedDataSetTarget; + if(oldTV->targetVariablesSize == newTV->targetVariablesSize) { + for(size_t i = 0; i < config->subscribedDataSet.subscribedDataSetTarget.targetVariablesSize; i++) { + if(!UA_NodeId_equal(&oldTV->targetVariables[i].targetVariable.targetNodeId, + &newTV->targetVariables[i].targetVariable.targetNodeId)) { + UA_Server_DataSetReader_createTargetVariables(server, currentDataSetReader->identifier, + newTV->targetVariablesSize, newTV->targetVariables); + } + } + } else { + UA_Server_DataSetReader_createTargetVariables(server, currentDataSetReader->identifier, + newTV->targetVariablesSize, newTV->targetVariables); + } + + UA_StatusCode res = UA_STATUSCODE_GOOD; +#ifdef UA_ENABLE_PUBSUB_MONITORING + if(currentDataSetReader->config.messageReceiveTimeout != config->messageReceiveTimeout) { + /* Update message receive timeout timer interval */ + currentDataSetReader->config.messageReceiveTimeout = config->messageReceiveTimeout; + res = server->config.pubSubConfig.monitoringInterface. + updateMonitoringInterval(server, currentDataSetReader->identifier, + UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, + currentDataSetReader); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Update DataSetReader message receive timeout timer failed."); + } + } +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + return res; } UA_StatusCode UA_Server_DataSetReader_getConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier, UA_DataSetReaderConfig *config) { - if(!config) { + if(!config) return UA_STATUSCODE_BADINVALIDARGUMENT; - } UA_DataSetReader *currentDataSetReader = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier); - if(!currentDataSetReader) { + if(!currentDataSetReader) return UA_STATUSCODE_BADNOTFOUND; - } UA_DataSetReaderConfig tmpReaderConfig; /* Deep copy of the actual config */ @@ -30605,72 +30961,193 @@ UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src, UA_DataSetReaderConfig *dst) { memset(dst, 0, sizeof(UA_DataSetReaderConfig)); UA_StatusCode retVal = UA_String_copy(&src->name, &dst->name); - if(retVal != UA_STATUSCODE_GOOD) { + if(retVal != UA_STATUSCODE_GOOD) return retVal; - } retVal = UA_Variant_copy(&src->publisherId, &dst->publisherId); - if(retVal != UA_STATUSCODE_GOOD) { + if(retVal != UA_STATUSCODE_GOOD) return retVal; - } dst->writerGroupId = src->writerGroupId; dst->dataSetWriterId = src->dataSetWriterId; + dst->expectedEncoding = src->expectedEncoding; retVal = UA_DataSetMetaDataType_copy(&src->dataSetMetaData, &dst->dataSetMetaData); - if(retVal != UA_STATUSCODE_GOOD) { + if(retVal != UA_STATUSCODE_GOOD) return retVal; - } dst->dataSetFieldContentMask = src->dataSetFieldContentMask; dst->messageReceiveTimeout = src->messageReceiveTimeout; /* Currently memcpy is used to copy the securityParameters */ memcpy(&dst->securityParameters, &src->securityParameters, sizeof(UA_PubSubSecurityParameters)); - retVal = UA_UadpDataSetReaderMessageDataType_copy(&src->messageSettings, &dst->messageSettings); - if(retVal != UA_STATUSCODE_GOOD) { + retVal = UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings); + if(retVal != UA_STATUSCODE_GOOD) return retVal; - } retVal = UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings); - if (retVal != UA_STATUSCODE_GOOD) { - return retVal; + if(retVal != UA_STATUSCODE_GOOD) + return retVal; + + if(src->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) { + retVal = UA_TargetVariables_copy(&src->subscribedDataSet.subscribedDataSetTarget, + &dst->subscribedDataSet.subscribedDataSetTarget); + } + return retVal; +} + +void +UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg) { + UA_String_clear(&cfg->name); + UA_Variant_clear(&cfg->publisherId); + UA_DataSetMetaDataType_clear(&cfg->dataSetMetaData); + UA_ExtensionObject_clear(&cfg->messageSettings); + UA_ExtensionObject_clear(&cfg->transportSettings); + if(cfg->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) { + UA_TargetVariables_clear(&cfg->subscribedDataSet.subscribedDataSetTarget); + } +} + +UA_StatusCode +UA_Server_DataSetReader_getState(UA_Server *server, UA_NodeId dataSetReaderIdentifier, + UA_PubSubState *state) { + + if((server == NULL) || (state == NULL)) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_DataSetReader *currentDataSetReader = + UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier); + if(currentDataSetReader == NULL) + return UA_STATUSCODE_BADNOTFOUND; + *state = currentDataSetReader->state; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_DataSetReader_setState_disabled(UA_Server *server, UA_DataSetReader *dsr) { + UA_StatusCode ret = UA_STATUSCODE_GOOD; + switch(dsr->state) { + case UA_PUBSUBSTATE_DISABLED: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_PAUSED: + dsr->state = UA_PUBSUBSTATE_DISABLED; + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_OPERATIONAL: +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* Stop MessageReceiveTimeout timer */ + if(dsr->msgRcvTimeoutTimerRunning == UA_TRUE) { + ret = server->config.pubSubConfig.monitoringInterface. + stopMonitoring(server, dsr->identifier, + UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr); + if(ret == UA_STATUSCODE_GOOD) { + dsr->msgRcvTimeoutTimerRunning = UA_FALSE; + } else { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Disable ReaderGroup failed. Stop message receive " + "timeout timer of DataSetReader '%.*s' failed.", + (int) dsr->config.name.length, dsr->config.name.data); + } + } +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + if(ret == UA_STATUSCODE_GOOD) + dsr->state = UA_PUBSUBSTATE_DISABLED; + return ret; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); } + return UA_STATUSCODE_BADINVALIDARGUMENT; +} +/* State machine methods not part of the open62541 state machine API */ +UA_StatusCode +UA_DataSetReader_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_DataSetReader *dataSetReader) { + switch(state) { + case UA_PUBSUBSTATE_DISABLED: + return UA_DataSetReader_setState_disabled(server, dataSetReader); + case UA_PUBSUBSTATE_PAUSED: + return UA_STATUSCODE_BADNOTSUPPORTED; + case UA_PUBSUBSTATE_OPERATIONAL: + dataSetReader->state = UA_PUBSUBSTATE_OPERATIONAL; + break; + case UA_PUBSUBSTATE_ERROR: + dataSetReader->state = UA_PUBSUBSTATE_ERROR; + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } return UA_STATUSCODE_GOOD; } +UA_StatusCode +UA_FieldTargetVariable_copy(const UA_FieldTargetVariable *src, UA_FieldTargetVariable *dst) { + /* Do a simple memcpy */ + memcpy(dst, src, sizeof(UA_FieldTargetVariable)); + return UA_FieldTargetDataType_copy(&src->targetVariable, &dst->targetVariable); +} + +UA_StatusCode +UA_TargetVariables_copy(const UA_TargetVariables *src, UA_TargetVariables *dst) { + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + memcpy(dst, src, sizeof(UA_TargetVariables)); + if(src->targetVariablesSize > 0) { + dst->targetVariables = (UA_FieldTargetVariable*) + UA_calloc(src->targetVariablesSize, sizeof(UA_FieldTargetVariable)); + if(!dst->targetVariables) + return UA_STATUSCODE_BADOUTOFMEMORY; + for(size_t i = 0; i < src->targetVariablesSize; i++) + retVal |= UA_FieldTargetVariable_copy(&src->targetVariables[i], &dst->targetVariables[i]); + } + return retVal; +} + +void +UA_TargetVariables_clear(UA_TargetVariables *subscribedDataSetTarget) { + for(size_t i = 0; i < subscribedDataSetTarget->targetVariablesSize; i++) { + UA_FieldTargetDataType_clear(&subscribedDataSetTarget->targetVariables[i].targetVariable); + } + if(subscribedDataSetTarget->targetVariablesSize > 0) + UA_free(subscribedDataSetTarget->targetVariables); + memset(subscribedDataSetTarget, 0, sizeof(UA_TargetVariables)); +} + /* This Method is used to initially set the SubscribedDataSet to * TargetVariablesType and to create the list of target Variables of a * SubscribedDataSetType. */ UA_StatusCode UA_Server_DataSetReader_createTargetVariables(UA_Server *server, UA_NodeId dataSetReaderIdentifier, - UA_TargetVariablesDataType *targetVariables) { - UA_StatusCode retval = UA_STATUSCODE_BADUNEXPECTEDERROR; - UA_DataSetReader* pDS = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier); - if(pDS == NULL) { + size_t targetVariablesSize, + const UA_FieldTargetVariable *targetVariables) { + UA_DataSetReader *dataSetReader = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier); + if(!dataSetReader) return UA_STATUSCODE_BADINVALIDARGUMENT; - } - if(pDS->subscribedDataSetTarget.targetVariablesSize > 0) { - UA_TargetVariablesDataType_deleteMembers(&pDS->subscribedDataSetTarget); - pDS->subscribedDataSetTarget.targetVariablesSize = 0; - pDS->subscribedDataSetTarget.targetVariables = NULL; + if(dataSetReader->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Create Target Variables failed. Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; } + if(dataSetReader->config.subscribedDataSet.subscribedDataSetTarget.targetVariablesSize > 0) + UA_TargetVariables_clear(&dataSetReader->config.subscribedDataSet.subscribedDataSetTarget); + /* Set subscribed dataset to TargetVariableType */ - pDS->subscribedDataSetType = UA_PUBSUB_SDS_TARGET; - retval = UA_TargetVariablesDataType_copy(targetVariables, &pDS->subscribedDataSetTarget); - return retval; + dataSetReader->config.subscribedDataSetType = UA_PUBSUB_SDS_TARGET; + UA_TargetVariables tmp; + tmp.targetVariablesSize = targetVariablesSize; + tmp.targetVariables = (UA_FieldTargetVariable*)(uintptr_t)targetVariables; + return UA_TargetVariables_copy(&tmp, &dataSetReader->config.subscribedDataSet.subscribedDataSetTarget); } -/* Adds Subscribed Variables from the DataSetMetaData for the given DataSet into - * the given parent node and creates the corresponding data in the - * targetVariables of the DataSetReader */ -UA_StatusCode -UA_Server_DataSetReader_addTargetVariables(UA_Server *server, UA_NodeId *parentNode, - UA_NodeId dataSetReaderIdentifier, - UA_SubscribedDataSetEnumType sdsType) { +/* This functionality of this API will be used in future to create mirror Variables - TODO */ +/* UA_StatusCode +UA_Server_DataSetReader_createDataSetMirror(UA_Server *server, UA_String *parentObjectNodeName, + UA_NodeId dataSetReaderIdentifier) { if((server == NULL) || (parentNode == NULL)) { return UA_STATUSCODE_BADINVALIDARGUMENT; } @@ -30681,12 +31158,18 @@ UA_Server_DataSetReader_addTargetVariables(UA_Server *server, UA_NodeId *parentN return UA_STATUSCODE_BADINVALIDARGUMENT; } - UA_TargetVariablesDataType targetVars; + if(pDataSetReader->configurationFrozen) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Add Target Variables failed. Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } // TODO: Frozen configuration variable in TargetVariable structure + + UA_TargetVariables targetVars; targetVars.targetVariablesSize = pDataSetReader->config.dataSetMetaData.fieldsSize; - targetVars.targetVariables = (UA_FieldTargetDataType*) - UA_calloc(targetVars.targetVariablesSize, sizeof(UA_FieldTargetDataType)); + targetVars.targetVariables = (UA_FieldTargetVariable *) + UA_calloc(targetVars.targetVariablesSize, sizeof(UA_FieldTargetVariable)); - for (size_t i = 0; i < pDataSetReader->config.dataSetMetaData.fieldsSize; i++) { + for(size_t i = 0; i < pDataSetReader->config.dataSetMetaData.fieldsSize; i++) { UA_VariableAttributes vAttr = UA_VariableAttributes_default; vAttr.valueRank = pDataSetReader->config.dataSetMetaData.fields[i].valueRank; if(pDataSetReader->config.dataSetMetaData.fields[i].arrayDimensionsSize > 0) { @@ -30727,7 +31210,7 @@ UA_Server_DataSetReader_addTargetVariables(UA_Server *server, UA_NodeId *parentN qn = UA_QUALIFIEDNAME(1, "SubscribedVariable"); } - /* Add variable to the given parent node */ + // Add variable to the given parent node UA_NodeId newNode; retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, *parentNode, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), qn, @@ -30742,151 +31225,1309 @@ UA_Server_DataSetReader_addTargetVariables(UA_Server *server, UA_NodeId *parentN "addVariableNode: error 0x%" PRIx32, retval); } - UA_FieldTargetDataType_init(&targetVars.targetVariables[i]); - targetVars.targetVariables[i].attributeId = UA_ATTRIBUTEID_VALUE; - UA_NodeId_copy(&newNode, &targetVars.targetVariables[i].targetNodeId); - UA_NodeId_deleteMembers(&newNode); + targetVars.targetVariables[i].targetVariable.attributeId = UA_ATTRIBUTEID_VALUE; + UA_NodeId_copy(&newNode, &targetVars.targetVariables[i].targetVariable.targetNodeId); + UA_NodeId_clear(&newNode); if(vAttr.arrayDimensionsSize > 0) { UA_Array_delete(vAttr.arrayDimensions, vAttr.arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); } } - if(sdsType == UA_PUBSUB_SDS_TARGET) { - retval = UA_Server_DataSetReader_createTargetVariables(server, pDataSetReader->identifier, - &targetVars); + UA_TargetVariables_clear(&targetVars); + return retval; +}*/ + +static void +DataSetReader_processRaw(UA_Server *server, UA_ReaderGroup *rg, + UA_DataSetReader *dsr, UA_DataSetMessage* msg) { + UA_LOG_TRACE(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received RAW Frame"); + msg->data.keyFrameData.fieldCount = (UA_UInt16) + dsr->config.dataSetMetaData.fieldsSize; + + size_t offset = 0; + for(size_t i = 0; i < dsr->config.dataSetMetaData.fieldsSize; i++) { + /* TODO The datatype reference should be part of the internal + * pubsub configuration to avoid the time-expensive lookup */ + const UA_DataType *type = + UA_findDataTypeWithCustom(&dsr->config.dataSetMetaData.fields[i].dataType, + server->config.customDataTypes); + msg->data.keyFrameData.rawFields.length += type->memSize; + UA_STACKARRAY(UA_Byte, value, type->memSize); + UA_StatusCode res = + UA_decodeBinaryInternal(&msg->data.keyFrameData.rawFields, + &offset, value, type, NULL); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error during Raw-decode KeyFrame field %u: %s", + (unsigned)i, UA_StatusCode_name(res)); + return; + } + + UA_FieldTargetVariable *tv = + &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i]; + + if(rg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) { + if (tv->beforeWrite) { + void *pData = (**tv->externalDataValue).value.data; + (**tv->externalDataValue).value.data = value; // set raw data as "preview" + tv->beforeWrite(server, + &dsr->identifier, + &dsr->linkedReaderGroup, + &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i].targetVariable.targetNodeId, + dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i].targetVariableContext, + tv->externalDataValue); + (**tv->externalDataValue).value.data = pData; // restore previous data pointer + } + memcpy((**tv->externalDataValue).value.data, value, type->memSize); + if(tv->afterWrite) + tv->afterWrite(server, &dsr->identifier, + &dsr->linkedReaderGroup, + &tv->targetVariable.targetNodeId, + tv->targetVariableContext, + tv->externalDataValue); + continue; /* No dynamic allocation for fixed-size msg, no need to _clear */ + } + + UA_WriteValue writeVal; + UA_WriteValue_init(&writeVal); + writeVal.attributeId = tv->targetVariable.attributeId; + writeVal.indexRange = tv->targetVariable.receiverIndexRange; + writeVal.nodeId = tv->targetVariable.targetNodeId; + UA_Variant_setScalar(&writeVal.value.value, value, type); + writeVal.value.hasValue = true; + res = UA_Server_write(server, &writeVal); + UA_clear(value, type); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error writing KeyFrame field %u: %s", + (unsigned)i, UA_StatusCode_name(res)); + } } +} - UA_TargetVariablesDataType_deleteMembers(&targetVars); - return retval; +static void +DataSetReader_processFixedSize(UA_Server *server, UA_ReaderGroup *rg, + UA_DataSetReader *dsr, UA_DataSetMessage *msg, + size_t fieldCount) { + for(size_t i = 0; i < fieldCount; i++) { + if(!msg->data.keyFrameData.dataSetFields[i].hasValue) + continue; + + UA_FieldTargetVariable *tv = + &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i]; + if(tv->targetVariable.attributeId != UA_ATTRIBUTEID_VALUE) + continue; + if (tv->beforeWrite) { + UA_DataValue *tmp = &msg->data.keyFrameData.dataSetFields[i]; + tv->beforeWrite(server, + &dsr->identifier, + &dsr->linkedReaderGroup, + &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i].targetVariable.targetNodeId, + dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i].targetVariableContext, + &tmp); + } + memcpy((**tv->externalDataValue).value.data, + msg->data.keyFrameData.dataSetFields[i].value.data, + msg->data.keyFrameData.dataSetFields[i].value.type->memSize); + if(tv->afterWrite) + tv->afterWrite(server, &dsr->identifier, &dsr->linkedReaderGroup, + &tv->targetVariable.targetNodeId, + tv->targetVariableContext, tv->externalDataValue); + } } void -UA_Server_DataSetReader_process(UA_Server *server, UA_DataSetReader *dataSetReader, - UA_DataSetMessage* dataSetMsg) { - if((dataSetReader == NULL) || (dataSetMsg == NULL) || (server == NULL)) { +UA_DataSetReader_process(UA_Server *server, UA_ReaderGroup *rg, + UA_DataSetReader *dsr, UA_DataSetMessage *msg) { + if(!dsr || !rg || !msg || !server) return; - } - if(!dataSetMsg->header.dataSetMessageValid) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "DataSetReader '%.*s': received a network message", + (int) dsr->config.name.length, dsr->config.name.data); + + if(!msg->header.dataSetMessageValid) { UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, "DataSetMessage is discarded: message is not valid"); - /* To Do check ConfigurationVersion*/ - /*if(dataSetMsg->header.configVersionMajorVersionEnabled) - * { - * if(dataSetMsg->header.configVersionMajorVersion != dataSetReader->config.dataSetMetaData.configurationVersion.majorVersion) - * { - * UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, "DataSetMessage is discarded: ConfigurationVersion MajorVersion does not match"); - * return; - * } - } */ + /* To Do check ConfigurationVersion */ + /* if(msg->header.configVersionMajorVersionEnabled) { + * if(msg->header.configVersionMajorVersion != + * dsr->config.dataSetMetaData.configurationVersion.majorVersion) { + * UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + * "DataSetMessage is discarded: ConfigurationVersion " + * "MajorVersion does not match"); + * return; + * } + * } */ return; } - if(dataSetMsg->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { - if(dataSetMsg->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) { - size_t anzFields = dataSetMsg->data.keyFrameData.fieldCount; - if(dataSetReader->config.dataSetMetaData.fieldsSize < anzFields) { - anzFields = dataSetReader->config.dataSetMetaData.fieldsSize; - } + if(msg->header.dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "DataSetMessage is discarded: Only keyframes are supported"); + return; + } - if(dataSetReader->subscribedDataSetTarget.targetVariablesSize < anzFields) { - anzFields = dataSetReader->subscribedDataSetTarget.targetVariablesSize; - } + /* Process message with raw encoding (realtime and non-realtime) */ + if(msg->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { + DataSetReader_processRaw(server, rg, dsr, msg); +#ifdef UA_ENABLE_PUBSUB_MONITORING + UA_DataSetReader_checkMessageReceiveTimeout(server, dsr); +#endif + return; + } - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - for(UA_UInt16 i = 0; i < anzFields; i++) { - if(dataSetMsg->data.keyFrameData.dataSetFields[i].hasValue) { - if(dataSetReader->subscribedDataSetTarget.targetVariables[i].attributeId == UA_ATTRIBUTEID_VALUE) { - retVal = UA_Server_writeValue(server, dataSetReader->subscribedDataSetTarget.targetVariables[i].targetNodeId, dataSetMsg->data.keyFrameData.dataSetFields[i].value); - if(retVal != UA_STATUSCODE_GOOD) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error Write Value KF %" PRIu16 ": 0x%"PRIx32, i, retVal); - } + /* Check and adjust the field count + * TODO Throw an error if non-matching? */ + size_t fieldCount = msg->data.keyFrameData.fieldCount; + if(dsr->config.dataSetMetaData.fieldsSize < fieldCount) + fieldCount = dsr->config.dataSetMetaData.fieldsSize; - } - else { - UA_WriteValue writeVal; - UA_WriteValue_init(&writeVal); - writeVal.attributeId = dataSetReader->subscribedDataSetTarget.targetVariables[i].attributeId; - writeVal.indexRange = dataSetReader->subscribedDataSetTarget.targetVariables[i].receiverIndexRange; - writeVal.nodeId = dataSetReader->subscribedDataSetTarget.targetVariables[i].targetNodeId; - UA_DataValue_copy(&dataSetMsg->data.keyFrameData.dataSetFields[i], &writeVal.value); - retVal = UA_Server_write(server, &writeVal); - if(retVal != UA_STATUSCODE_GOOD) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error Write KF %" PRIu16 ": 0x%" PRIx32, i, retVal); - } + if(dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariablesSize < fieldCount) + fieldCount = dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariablesSize; - } + /* Process message with fixed size fields (realtime capable) */ + if(rg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) { + DataSetReader_processFixedSize(server, rg, dsr, msg, fieldCount); +#ifdef UA_ENABLE_PUBSUB_MONITORING + UA_DataSetReader_checkMessageReceiveTimeout(server, dsr); +#endif + return; + } - } + /* Write the message fields via the write service (non realtime) */ + UA_StatusCode res = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < fieldCount; i++) { + if(!msg->data.keyFrameData.dataSetFields[i].hasValue) + continue; - } + UA_FieldTargetVariable *tv = + &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i]; + UA_WriteValue writeVal; + UA_WriteValue_init(&writeVal); + writeVal.attributeId = tv->targetVariable.attributeId; + writeVal.indexRange = tv->targetVariable.receiverIndexRange; + writeVal.nodeId = tv->targetVariable.targetNodeId; + writeVal.value = msg->data.keyFrameData.dataSetFields[i]; + res = UA_Server_write(server, &writeVal); + if(res != UA_STATUSCODE_GOOD) + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error writing KeyFrame field %u: %s", + (unsigned)i, UA_StatusCode_name(res)); + } + +#ifdef UA_ENABLE_PUBSUB_MONITORING + UA_DataSetReader_checkMessageReceiveTimeout(server, dsr); +#endif +} + +#ifdef UA_ENABLE_PUBSUB_MONITORING + +void +UA_DataSetReader_checkMessageReceiveTimeout(UA_Server *server, + UA_DataSetReader *dsr) { + UA_assert(server != 0); + UA_assert(dsr != 0); + + /* If previous reader state was error (because we haven't received messages + * and ran into timeout) we should set the state back to operational */ + if(dsr->state == UA_PUBSUBSTATE_ERROR) { + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, dsr); + if(server->config.pubSubConfig.stateChangeCallback != 0) { + server->config.pubSubConfig.stateChangeCallback(&dsr->identifier, + UA_PUBSUBSTATE_OPERATIONAL, + UA_STATUSCODE_GOOD); + } + } + + /* Stop message receive timeout timer */ + UA_StatusCode res; + if(dsr->msgRcvTimeoutTimerRunning) { + res = server->config.pubSubConfig.monitoringInterface. + stopMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr); + if(res == UA_STATUSCODE_GOOD) { + dsr->msgRcvTimeoutTimerRunning = false; + } else { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "DataSetReader '%.*s': stop receive timeout timer failed", + (int)dsr->config.name.length, dsr->config.name.data); + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dsr); } + } + + /* Start message receive timeout timer */ + res = server->config.pubSubConfig.monitoringInterface. + startMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER, + UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr); + if(res == UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Info: DataSetReader '%.*s': start receive timeout timer", + (int)dsr->config.name.length, dsr->config.name.data); + dsr->msgRcvTimeoutTimerRunning = true; + } else { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Starting Message Receive Timeout timer failed."); + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dsr); + } +} + +/* Timeout callback for DataSetReader MessageReceiveTimeout handling */ +void +UA_DataSetReader_handleMessageReceiveTimeout(UA_Server *server, + void *dataSetReader) { + if(!server || !dataSetReader) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_DataSetReader_handleMessageReceiveTimeout(): " + "null pointer param"); + return; + } + + UA_DataSetReader *dsr = (UA_DataSetReader*) dataSetReader; + if(dsr->componentType != UA_PUBSUB_COMPONENT_DATASETREADER) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_DataSetReader_handleMessageReceiveTimeout(): " + "input param is not of type DataSetReader"); + return; + } + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_DataSetReader_handleMessageReceiveTimeout(): " + "MessageReceiveTimeout occurred at DataSetReader " + "'%.*s': MessageReceiveTimeout = %f Timer Id = %u ", + (int)dsr->config.name.length, dsr->config.name.data, + dsr->config.messageReceiveTimeout, + (UA_UInt32) dsr->msgRcvTimeoutTimerId); + + UA_ServerConfig *pConfig = UA_Server_getConfig(server); + if(pConfig->pubSubConfig.stateChangeCallback != 0) { + pConfig->pubSubConfig.stateChangeCallback(&dsr->identifier, + UA_PUBSUBSTATE_ERROR, + UA_STATUSCODE_BADTIMEOUT); + } + + UA_StatusCode res = + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dsr); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_DataSetReader_handleMessageReceiveTimeout(): " + "setting pubsub state failed"); } } +#endif /* UA_ENABLE_PUBSUB_MONITORING */ -void UA_DataSetReader_delete(UA_Server *server, UA_DataSetReader *dataSetReader) { +static void +UA_DataSetReader_clear(UA_Server *server, UA_DataSetReader *dsr) { /* Delete DataSetReader config */ - UA_String_deleteMembers(&dataSetReader->config.name); - UA_Variant_deleteMembers(&dataSetReader->config.publisherId); - UA_DataSetMetaDataType_deleteMembers(&dataSetReader->config.dataSetMetaData); - UA_UadpDataSetReaderMessageDataType_deleteMembers(&dataSetReader->config.messageSettings); - UA_ExtensionObject_clear(&dataSetReader->config.transportSettings); - UA_TargetVariablesDataType_deleteMembers(&dataSetReader->subscribedDataSetTarget); + UA_DataSetReaderConfig_clear(&dsr->config); /* Delete DataSetReader */ - UA_ReaderGroup* pGroup = UA_ReaderGroup_findRGbyId(server, dataSetReader->linkedReaderGroup); - if(pGroup != NULL) { - pGroup->readersCount--; + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, dsr->linkedReaderGroup); + if(rg) + rg->readersCount--; + + UA_NodeId_clear(&dsr->identifier); + UA_NodeId_clear(&dsr->linkedReaderGroup); + if(dsr->config.subscribedDataSetType == UA_PUBSUB_SDS_TARGET) { + UA_TargetVariables_clear(&dsr->config.subscribedDataSet.subscribedDataSetTarget); + } else { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_DataSetReader_clear(): unsupported subscribed dataset enum type"); } - UA_NodeId_deleteMembers(&dataSetReader->identifier); - UA_NodeId_deleteMembers(&dataSetReader->linkedReaderGroup); /* Remove DataSetReader from group */ - LIST_REMOVE(dataSetReader, listEntry); + LIST_REMOVE(dsr, listEntry); + /* Free memory allocated for DataSetReader */ - UA_free(dataSetReader); + UA_free(dsr); +} + +static void +processMessageWithReader(UA_Server *server, UA_ReaderGroup *readerGroup, + UA_DataSetReader *reader, UA_NetworkMessage *msg) { + UA_Byte totalDataSets = 1; + if(msg->payloadHeaderEnabled) + totalDataSets = msg->payloadHeader.dataSetPayloadHeader.count; + for(UA_Byte i = 0; i < totalDataSets; i++) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Process Msg with DataSetReader!"); + UA_DataSetReader_process(server, readerGroup, reader, + &msg->payload.dataSetPayload.dataSetMessages[i]); + } } UA_StatusCode -UA_Server_processNetworkMessage(UA_Server *server, UA_NetworkMessage *pMsg, - UA_PubSubConnection *pConnection) { - UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(!pMsg || !pConnection) +UA_Server_processNetworkMessage(UA_Server *server, UA_PubSubConnection *connection, + UA_NetworkMessage* msg) { + if(!msg || !connection) return UA_STATUSCODE_BADINVALIDARGUMENT; - /* To Do Handle multiple DataSetMessage for one NetworkMessage */ /* To Do The condition pMsg->dataSetClassIdEnabled * Here some filtering is possible */ + if(!msg->publisherIdEnabled) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Cannot process DataSetReader without PublisherId"); + return UA_STATUSCODE_BADNOTIMPLEMENTED; /* TODO: Handle DSR without PublisherId */ + } + + /* There can be several readers listening for the same network message */ + UA_Boolean processed = false; + UA_ReaderGroup *readerGroup; + UA_DataSetReader *reader; + LIST_FOREACH(readerGroup, &connection->readerGroups, listEntry) { + LIST_FOREACH(reader, &readerGroup->readers, listEntry) { + UA_StatusCode retval = checkReaderIdentifier(server, msg, reader); + if(retval == UA_STATUSCODE_GOOD) { + processed = true; + processMessageWithReader(server, readerGroup, reader, msg); + } + } + } + + if(!processed) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Dataset reader not found. Check PublisherID, WriterGroupID " + "and DatasetWriterID"); + } + + return UA_STATUSCODE_GOOD; +} + +/******************************************************************************** + * Functionality related to decoding, decrypting and processing network messages + * as a subscriber + ********************************************************************************/ + +#define MIN_PAYLOAD_SIZE_ETHERNET 46 + +/* Delete the payload value of every decoded DataSet field */ +static void UA_DataSetMessage_freeDecodedPayload(UA_DataSetMessage *dsm) { + if(dsm->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + for(size_t i = 0; i < dsm->data.keyFrameData.fieldCount; i++) { +#ifdef UA_ENABLE_PUBSUB_BUFMALLOC + UA_Variant_init(&dsm->data.keyFrameData.dataSetFields[i].value); +#else + UA_Variant_clear(&dsm->data.keyFrameData.dataSetFields[i].value); +#endif + } + } + else if(dsm->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + for(size_t i = 0; i < dsm->data.keyFrameData.fieldCount; i++) { +#ifdef UA_ENABLE_PUBSUB_BUFMALLOC + UA_DataValue_init(&dsm->data.keyFrameData.dataSetFields[i]); +#else + UA_DataValue_clear(&dsm->data.keyFrameData.dataSetFields[i]); +#endif + } + } +} + +UA_StatusCode +decodeNetworkMessage(UA_Server *server, UA_ByteString *buffer, size_t *pos, + UA_NetworkMessage *nm, UA_PubSubConnection *connection) { +#ifdef UA_DEBUG_DUMP_PKGS + UA_dump_hex_pkg(buffer->data, buffer->length); +#endif + + UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(buffer, pos, nm); + UA_CHECK_STATUS_ERROR(rv, return rv, + &server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub receive. decoding headers failed"); + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_Boolean processed = false; + UA_ReaderGroup *readerGroup; + UA_DataSetReader *reader; + + /* Choose a correct readergroup for decrypt/verify this message + * (there could be multiple) */ + LIST_FOREACH(readerGroup, &connection->readerGroups, listEntry) { + LIST_FOREACH(reader, &readerGroup->readers, listEntry) { + UA_StatusCode retval = checkReaderIdentifier(server, nm, reader); + if(retval == UA_STATUSCODE_GOOD) { + processed = true; + rv = verifyAndDecryptNetworkMessage(&server->config.logger, buffer, pos, + nm, readerGroup); + UA_CHECK_STATUS_WARN(rv, return rv, + &server->config.logger, UA_LOGCATEGORY_SERVER, + "Subscribe failed. verify and decrypt network message failed."); + +#ifdef UA_DEBUG_DUMP_PKGS + UA_dump_hex_pkg(buffer->data, buffer->length); +#endif + /* break out of all loops when first verify & decrypt was successful */ + goto loops_exit; + } + } + } + +loops_exit: + if(!processed) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Dataset reader not found. Check PublisherId, " + "WriterGroupId and DatasetWriterId"); + /* Possible multicast scenario: there are multiple connections (with one + * or more ReaderGroups) within a multicast group every connection + * receives all network messages, even if some of them are not meant for + * the connection currently processed -> therefore it is ok if the + * connection does not have a DataSetReader for every received network + * message. We must not return an error here, but continue with the + * buffer decoding and see if we have a matching DataSetReader for the + * next network message. */ + } +#endif + + rv = UA_NetworkMessage_decodePayload(buffer, pos, nm); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_decodeFooters(buffer, pos, nm); + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; +} + +static +UA_StatusCode +decodeAndProcessNetworkMessage(UA_Server *server, UA_ReaderGroup *readerGroup, + UA_PubSubConnection *connection, + UA_ByteString *buffer) { + UA_NetworkMessage nm; + memset(&nm, 0, sizeof(UA_NetworkMessage)); + size_t currentPosition = 0; + + UA_StatusCode rv = UA_STATUSCODE_GOOD; + rv = decodeNetworkMessage(server, buffer, ¤tPosition, &nm, connection); + UA_CHECK_STATUS_WARN(rv, goto cleanup, &server->config.logger, UA_LOGCATEGORY_SERVER, + "Subscribe failed. verify, decrypt and decode network message failed."); + + rv = UA_Server_processNetworkMessage(server, connection, &nm); + // TODO: check what action to perform on error (nothing?) + UA_CHECK_STATUS_WARN(rv, (void)0, &server->config.logger, UA_LOGCATEGORY_SERVER, + "Subscribe failed. process network message failed."); + +cleanup: + UA_NetworkMessage_clear(&nm); + return rv; +} + +static +UA_StatusCode +decodeAndProcessNetworkMessageRT(UA_Server *server, UA_ReaderGroup *readerGroup, + UA_PubSubConnection *connection, + UA_ByteString *buffer) { +#ifdef UA_ENABLE_PUBSUB_BUFMALLOC + useMembufAlloc(); +#endif + + /* Considering max DSM as 1 + * TODO: Process with the static value source */ + size_t currentPosition = 0; + UA_DataSetReader *dataSetReader = LIST_FIRST(&readerGroup->readers); + UA_NetworkMessage *nm = dataSetReader->bufferedMessage.nm; + + /* Decode only the necessary offset and update the networkMessage */ + UA_StatusCode res = + UA_NetworkMessage_updateBufferedNwMessage(&dataSetReader->bufferedMessage, + buffer, ¤tPosition); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub receive. Unknown field type."); + res = UA_STATUSCODE_UNCERTAIN; + goto cleanup; + } + + /* Check the decoded message is the expected one + * TODO: PublisherID check after modification in NM to support all datatypes */ + if(nm->groupHeader.writerGroupId != dataSetReader->config.writerGroupId || + *nm->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != dataSetReader->config.dataSetWriterId) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub receive. Unknown message received. Will not be processed."); + res = UA_STATUSCODE_UNCERTAIN; + goto cleanup; + } + + UA_DataSetReader_process(server, readerGroup, dataSetReader, + nm->payload.dataSetPayload.dataSetMessages); + + cleanup: + UA_DataSetMessage_freeDecodedPayload(nm->payload.dataSetPayload.dataSetMessages); +#ifdef UA_ENABLE_PUBSUB_BUFMALLOC + useNormalAlloc(); +#endif + return res; +} + +typedef struct { + UA_Server *server; + UA_PubSubConnection *connection; + UA_ReaderGroup *readerGroup; +} UA_RGContext; + +static UA_StatusCode +decodeAndProcessFun(UA_PubSubChannel *channel, void *cbContext, + const UA_ByteString *buffer) { + UA_ByteString mutableBuffer = {buffer->length, buffer->data}; + UA_RGContext *ctx = (UA_RGContext*) cbContext; + return decodeAndProcessNetworkMessage(ctx->server, ctx->readerGroup, + ctx->connection, &mutableBuffer); +} + +static UA_StatusCode +decodeAndProcessFunRT(UA_PubSubChannel *channel, void *cbContext, + const UA_ByteString *buffer) { + UA_ByteString mutableBuffer = {buffer->length, buffer->data}; + UA_RGContext *ctx = (UA_RGContext*) cbContext; + return decodeAndProcessNetworkMessageRT(ctx->server, ctx->readerGroup, + ctx->connection, &mutableBuffer); +} + +UA_StatusCode +receiveBufferedNetworkMessage(UA_Server *server, UA_ReaderGroup *readerGroup, + UA_PubSubConnection *connection) { + UA_RGContext ctx = {server, connection, readerGroup}; + UA_PubSubReceiveCallback receiveCB; + if(readerGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) + receiveCB = decodeAndProcessFunRT; + else + receiveCB = decodeAndProcessFun; + + /* TODO: Move the TransportSettings to to the readerGroupConfig. So we can + * use it here instead of a NULL pointer. */ + UA_StatusCode rv = + connection->channel->receive(connection->channel, NULL, + receiveCB, &ctx, + readerGroup->config.timeout); + + // TODO attention: here rv is ok if UA_STATUSCODE_GOOD != rv + UA_CHECK_WARN(!UA_StatusCode_isBad(rv), return rv, + &server->config.logger, UA_LOGCATEGORY_SERVER, + "SubscribeCallback(): Connection receive failed!"); + + return UA_STATUSCODE_GOOD; +} + +#endif /* UA_ENABLE_PUBSUB */ + +/**** amalgamated original file "/src/pubsub/ua_pubsub_readergroup.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner) + * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes) + */ + + + +#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ + + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL +#endif + +UA_ReaderGroup * +UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier) { + UA_PubSubConnection *pubSubConnection; + TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){ + UA_ReaderGroup* readerGroup = NULL; + LIST_FOREACH(readerGroup, &pubSubConnection->readerGroups, listEntry) { + if(UA_NodeId_equal(&identifier, &readerGroup->identifier)) + return readerGroup; + } + } + return NULL; +} + +UA_DataSetReader *UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier) { + UA_PubSubConnection *pubSubConnection; + TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){ + UA_ReaderGroup* readerGroup = NULL; + LIST_FOREACH(readerGroup, &pubSubConnection->readerGroups, listEntry) { + UA_DataSetReader *tmpReader; + LIST_FOREACH(tmpReader, &readerGroup->readers, listEntry) { + if(UA_NodeId_equal(&tmpReader->identifier, &identifier)) + return tmpReader; + } + } + } + return NULL; +} + +/* Clear ReaderGroup */ +static void +UA_Server_ReaderGroup_clear(UA_Server* server, UA_ReaderGroup *readerGroup); + +/* ReaderGroup Config Handling */ + +UA_StatusCode +UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src, + UA_ReaderGroupConfig *dst) { + memcpy(dst, src, sizeof(UA_ReaderGroupConfig)); + + UA_StatusCode res = UA_String_copy(&src->name, &dst->name); + if(res != UA_STATUSCODE_GOOD) + return res; + + res = UA_Array_copy(src->groupProperties, src->groupPropertiesSize, + (void**)&dst->groupProperties, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + if(res != UA_STATUSCODE_GOOD) { + UA_String_clear(&dst->name); + return res; + } + dst->groupPropertiesSize = src->groupPropertiesSize; + return UA_STATUSCODE_GOOD; +} + +void +UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig) { + UA_String_clear(&readerGroupConfig->name); + UA_Array_delete(readerGroupConfig->groupProperties, + readerGroupConfig->groupPropertiesSize, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + readerGroupConfig->groupProperties = NULL; + readerGroupConfig->groupPropertiesSize = 0; +} + +/* ReaderGroup Lifecycle */ + +UA_StatusCode +UA_Server_addReaderGroup(UA_Server *server, UA_NodeId connectionIdentifier, + const UA_ReaderGroupConfig *readerGroupConfig, + UA_NodeId *readerGroupIdentifier) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + /* Check for valid readergroup configuration */ + if(!readerGroupConfig) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + if(!readerGroupConfig->pubsubManagerCallback.addCustomCallback && + readerGroupConfig->enableBlockingSocket) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Adding ReaderGroup failed, blocking socket functionality " + "only supported in customcallback"); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + + /* Search the connection by the given connectionIdentifier */ + UA_PubSubConnection *currentConnectionContext = + UA_PubSubConnection_findConnectionbyId(server, connectionIdentifier); + if(!currentConnectionContext) + return UA_STATUSCODE_BADNOTFOUND; + + if(currentConnectionContext->configurationFrozen){ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Adding ReaderGroup failed. Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + /* Regist (bind) the connection channel if it is not already registered */ + if(!currentConnectionContext->isRegistered) { + retval |= UA_PubSubConnection_regist(server, &connectionIdentifier); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Allocate memory for new reader group */ + UA_ReaderGroup *newGroup = (UA_ReaderGroup *)UA_calloc(1, sizeof(UA_ReaderGroup)); + if(!newGroup) + return UA_STATUSCODE_BADOUTOFMEMORY; + + newGroup->componentType = UA_PUBSUB_COMPONENT_READERGROUP; + /* Generate nodeid for the readergroup identifier */ + newGroup->linkedConnection = currentConnectionContext->identifier; + + /* Deep copy of the config */ + retval |= UA_ReaderGroupConfig_copy(readerGroupConfig, &newGroup->config); + /* Check user configured params and define it accordingly */ + if(newGroup->config.subscribingInterval <= 0.0) + newGroup->config.subscribingInterval = 5; // Set default to 5 ms + + if(newGroup->config.enableBlockingSocket) + newGroup->config.timeout = 0; // Set timeout to 0 for blocking socket + + if((!newGroup->config.enableBlockingSocket) && (!newGroup->config.timeout)) + newGroup->config.timeout = 1000; /* Set default to 1ms socket timeout + when non-blocking socket allows with + zero timeout */ + + LIST_INSERT_HEAD(¤tConnectionContext->readerGroups, newGroup, listEntry); + currentConnectionContext->readerGroupsSize++; + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + retval |= addReaderGroupRepresentation(server, newGroup); +#else + UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, + &newGroup->identifier); +#endif + if(readerGroupIdentifier) + UA_NodeId_copy(&newGroup->identifier, readerGroupIdentifier); + + return retval; +} + +UA_StatusCode +UA_Server_removeReaderGroup(UA_Server *server, UA_NodeId groupIdentifier) { + UA_ReaderGroup* readerGroup = + UA_ReaderGroup_findRGbyId(server, groupIdentifier); + if(readerGroup == NULL) + return UA_STATUSCODE_BADNOTFOUND; + + if(readerGroup->configurationFrozen){ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Remove ReaderGroup failed. Subscriber configuration is frozen."); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + } + + /* Search the connection to which the given readergroup is connected to */ + UA_PubSubConnection *connection = + UA_PubSubConnection_findConnectionbyId(server, readerGroup->linkedConnection); + if(connection == NULL) + return UA_STATUSCODE_BADNOTFOUND; + + /* Unregister subscribe callback */ + if(readerGroup->state == UA_PUBSUBSTATE_OPERATIONAL) + UA_ReaderGroup_removeSubscribeCallback(server, readerGroup); + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + removeReaderGroupRepresentation(server, readerGroup); +#endif + + /* UA_Server_ReaderGroup_clear also removes itself from the list */ + UA_Server_ReaderGroup_clear(server, readerGroup); + + /* Remove readerGroup from Connection */ + LIST_REMOVE(readerGroup, listEntry); + UA_free(readerGroup); + return UA_STATUSCODE_GOOD; +} + +/* TODO: Implement +UA_StatusCode +UA_Server_ReaderGroup_updateConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, + const UA_ReaderGroupConfig *config) { + return UA_STATUSCODE_BADNOTIMPLEMENTED; +} +*/ + +UA_StatusCode +UA_Server_ReaderGroup_getConfig(UA_Server *server, UA_NodeId readerGroupIdentifier, + UA_ReaderGroupConfig *config) { + if(!config) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + /* Identify the readergroup through the readerGroupIdentifier */ + UA_ReaderGroup *currentReaderGroup = + UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier); + if(!currentReaderGroup) + return UA_STATUSCODE_BADNOTFOUND; + + UA_ReaderGroupConfig tmpReaderGroupConfig; + /* deep copy of the actual config */ + UA_ReaderGroupConfig_copy(¤tReaderGroup->config, &tmpReaderGroupConfig); + *config = tmpReaderGroupConfig; + return UA_STATUSCODE_GOOD; +} + +static void +UA_Server_ReaderGroup_clear(UA_Server* server, UA_ReaderGroup *readerGroup) { + UA_ReaderGroupConfig_clear(&readerGroup->config); UA_DataSetReader *dataSetReader; - retval = getReaderFromIdentifier(server, pMsg, &dataSetReader, pConnection); - if(retval != UA_STATUSCODE_GOOD) { - return retval; + UA_DataSetReader *tmpDataSetReader; + LIST_FOREACH_SAFE(dataSetReader, &readerGroup->readers, listEntry, tmpDataSetReader) { + UA_Server_removeDataSetReader(server, dataSetReader->identifier); + } + UA_PubSubConnection* pConn = + UA_PubSubConnection_findConnectionbyId(server, readerGroup->linkedConnection); + if(pConn != NULL) + pConn->readerGroupsSize--; + + /* Delete ReaderGroup and its members */ + UA_NodeId_clear(&readerGroup->linkedConnection); + UA_NodeId_clear(&readerGroup->identifier); + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + if(readerGroup->config.securityPolicy && readerGroup->securityPolicyContext) { + readerGroup->config.securityPolicy->deleteContext(readerGroup->securityPolicyContext); + readerGroup->securityPolicyContext = NULL; } +#endif + + UA_ReaderGroupConfig_clear(&readerGroup->config); +} + +UA_StatusCode +UA_Server_ReaderGroup_getState(UA_Server *server, UA_NodeId readerGroupIdentifier, + UA_PubSubState *state) { + if((server == NULL) || (state == NULL)) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_ReaderGroup *currentReaderGroup = + UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier); + if(!currentReaderGroup) + return UA_STATUSCODE_BADNOTFOUND; + *state = currentReaderGroup->state; + return UA_STATUSCODE_GOOD; +} + +/* ReaderGroup State */ +static UA_StatusCode +UA_ReaderGroup_setPubSubState_disable(UA_Server *server, + UA_ReaderGroup *rg) { + UA_DataSetReader *dataSetReader; + switch(rg->state) { + case UA_PUBSUBSTATE_DISABLED: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_PAUSED: + break; + case UA_PUBSUBSTATE_OPERATIONAL: + UA_ReaderGroup_removeSubscribeCallback(server, rg); + LIST_FOREACH(dataSetReader, &rg->readers, listEntry) { + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, + dataSetReader); + } + rg->state = UA_PUBSUBSTATE_DISABLED; + break; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Unknown PubSub state!"); + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_ReaderGroup_setPubSubState_paused(UA_Server *server, + UA_ReaderGroup *rg) { UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, - "DataSetReader found with PublisherId"); + "PubSub state paused is unsupported at the moment!"); + switch(rg->state) { + case UA_PUBSUBSTATE_DISABLED: + break; + case UA_PUBSUBSTATE_PAUSED: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_OPERATIONAL: + break; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Unknown PubSub state!"); + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_BADNOTSUPPORTED; +} + +static UA_StatusCode +UA_ReaderGroup_setPubSubState_operational(UA_Server *server, + UA_ReaderGroup *rg) { + UA_DataSetReader *dataSetReader; + switch(rg->state) { + case UA_PUBSUBSTATE_DISABLED: + LIST_FOREACH(dataSetReader, &rg->readers, listEntry) { + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, dataSetReader); + } + UA_ReaderGroup_addSubscribeCallback(server, rg); + rg->state = UA_PUBSUBSTATE_OPERATIONAL; + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_PAUSED: + break; + case UA_PUBSUBSTATE_OPERATIONAL: + return UA_STATUSCODE_GOOD; + case UA_PUBSUBSTATE_ERROR: + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Unknown PubSub state!"); + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_BADNOTSUPPORTED; +} + +static UA_StatusCode +UA_ReaderGroup_setPubSubState_error(UA_Server *server, + UA_ReaderGroup *rg) { + UA_DataSetReader *dataSetReader; + switch(rg->state) { + case UA_PUBSUBSTATE_DISABLED: + break; + case UA_PUBSUBSTATE_PAUSED: + break; + case UA_PUBSUBSTATE_OPERATIONAL: + UA_ReaderGroup_removeSubscribeCallback(server, rg); + LIST_FOREACH(dataSetReader, &rg->readers, listEntry){ + UA_DataSetReader_setPubSubState(server, UA_PUBSUBSTATE_ERROR, dataSetReader); + } + break; + case UA_PUBSUBSTATE_ERROR: + return UA_STATUSCODE_GOOD; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Unknown PubSub state!"); + return UA_STATUSCODE_BADINTERNALERROR; + } + rg->state = UA_PUBSUBSTATE_ERROR; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_ReaderGroup_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_ReaderGroup *readerGroup) { + switch(state) { + case UA_PUBSUBSTATE_DISABLED: + return UA_ReaderGroup_setPubSubState_disable(server, readerGroup); + case UA_PUBSUBSTATE_PAUSED: + return UA_ReaderGroup_setPubSubState_paused(server, readerGroup); + case UA_PUBSUBSTATE_OPERATIONAL: + return UA_ReaderGroup_setPubSubState_operational(server, readerGroup); + case UA_PUBSUBSTATE_ERROR: + return UA_ReaderGroup_setPubSubState_error(server, readerGroup); + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Received unknown PubSub state!"); + break; + } + return UA_STATUSCODE_BADINVALIDARGUMENT; +} + +UA_StatusCode +UA_Server_setReaderGroupOperational(UA_Server *server, const UA_NodeId readerGroupId){ + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId); + if(!rg) + return UA_STATUSCODE_BADNOTFOUND; + return UA_ReaderGroup_setPubSubState(server, UA_PUBSUBSTATE_OPERATIONAL, rg); +} + +UA_StatusCode +UA_Server_setReaderGroupDisabled(UA_Server *server, const UA_NodeId readerGroupId){ + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId); + if(!rg) + return UA_STATUSCODE_BADNOTFOUND; + return UA_ReaderGroup_setPubSubState(server, UA_PUBSUBSTATE_DISABLED, rg); +} + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION +UA_StatusCode +UA_Server_setReaderGroupEncryptionKeys(UA_Server *server, const UA_NodeId readerGroup, + UA_UInt32 securityTokenId, + const UA_ByteString signingKey, + const UA_ByteString encryptingKey, + const UA_ByteString keyNonce) { + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroup); + UA_CHECK_MEM(rg, return UA_STATUSCODE_BADNOTFOUND); + + UA_CHECK_MEM_WARN(rg->config.securityPolicy, return UA_STATUSCODE_BADINTERNALERROR, + &server->config.logger, UA_LOGCATEGORY_SERVER, + "No SecurityPolicy configured for the ReaderGroup"); + + if(securityTokenId != rg->securityTokenId) { + rg->securityTokenId = securityTokenId; + rg->nonceSequenceNumber = 1; + } + + /* Create a new context */ + if(!rg->securityPolicyContext) { + return rg->config.securityPolicy-> + newContext(rg->config.securityPolicy->policyContext, + &signingKey, &encryptingKey, &keyNonce, + &rg->securityPolicyContext); + } + + /* Update the context */ + return rg->config.securityPolicy-> + setSecurityKeys(rg->securityPolicyContext, &signingKey, + &encryptingKey, &keyNonce); +} +#endif + +/* Freezing of the configuration */ + +UA_StatusCode +UA_Server_freezeReaderGroupConfiguration(UA_Server *server, + const UA_NodeId readerGroupId) { + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId); + if(!rg) + return UA_STATUSCODE_BADNOTFOUND; + + /* PubSubConnection freezeCounter++ */ + UA_NodeId pubSubConnectionId = rg->linkedConnection; + UA_PubSubConnection *pubSubConnection = + UA_PubSubConnection_findConnectionbyId(server, pubSubConnectionId); + pubSubConnection->configurationFreezeCounter++; + pubSubConnection->configurationFrozen = UA_TRUE; + + /* ReaderGroup freeze */ + /* TODO: Clarify on the freeze functionality in multiple DSR, multiple + * networkMessage conf in a RG */ + rg->configurationFrozen = UA_TRUE; + + /* DataSetReader freeze */ + UA_DataSetReader *dataSetReader; + UA_UInt16 dsrCount = 0; + LIST_FOREACH(dataSetReader, &rg->readers, listEntry){ + dataSetReader->configurationFrozen = UA_TRUE; + dsrCount++; + /* TODO: Configuration frozen for subscribedDataSet once + * UA_Server_DataSetReader_addTargetVariables API modified to support + * adding target variable one by one or in a group stored in a list. */ + } + + /* Not rt, we don't have to adjust anything */ + if(rg->config.rtLevel != UA_PUBSUB_RT_FIXED_SIZE) + return UA_STATUSCODE_GOOD; + + if(dsrCount > 1) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Mutiple DSR in a readerGroup not supported in RT " + "fixed size configuration"); + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + + dataSetReader = LIST_FIRST(&rg->readers); + + /* Support only to UADP encoding */ + if(dataSetReader->config.messageSettings.content.decoded.type != + &UA_TYPES[UA_TYPES_UADPDATASETREADERMESSAGEDATATYPE]) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: Non-RT capable encoding."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + + size_t fieldsSize = dataSetReader->config.dataSetMetaData.fieldsSize; + for(size_t i = 0; i < fieldsSize; i++) { + UA_FieldTargetVariable *tv = + &dataSetReader->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i]; + const UA_VariableNode *rtNode = (const UA_VariableNode *) + UA_NODESTORE_GET(server, &tv->targetVariable.targetNodeId); + if(rtNode != NULL && + rtNode->valueBackend.backendType != UA_VALUEBACKENDTYPE_EXTERNAL) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: PDS contains field " + "without external data source."); + UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode); + return UA_STATUSCODE_BADNOTSUPPORTED; + } - UA_Byte anzDataSets = 1; - if(pMsg->payloadHeaderEnabled) - anzDataSets = pMsg->payloadHeader.dataSetPayloadHeader.count; - for(UA_Byte iterator = 0; iterator < anzDataSets; iterator++) { - UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "Process Msg with DataSetReader!"); - UA_Server_DataSetReader_process(server, dataSetReader, - &pMsg->payload.dataSetPayload.dataSetMessages[iterator]); + UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode); + + UA_FieldMetaData *field = &dataSetReader->config.dataSetMetaData.fields[i]; + if((UA_NodeId_equal(&field->dataType, &UA_TYPES[UA_TYPES_STRING].typeId) || + UA_NodeId_equal(&field->dataType, &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) && + field->maxStringLength == 0) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: " + "PDS contains String/ByteString with dynamic length."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } else if(!UA_DataType_isNumeric(UA_findDataType(&field->dataType)) && + !UA_NodeId_equal(&field->dataType, &UA_TYPES[UA_TYPES_BOOLEAN].typeId)) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub-RT configuration fail: " + "PDS contains variable with dynamic size."); + return UA_STATUSCODE_BADNOTSUPPORTED; + } } - /* To Do Handle when dataSetReader parameters are null for publisherId - * and zero for WriterGroupId and DataSetWriterId */ + UA_DataSetMessage *dsm = (UA_DataSetMessage *) UA_calloc(1, sizeof(UA_DataSetMessage)); + if(!dsm) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub RT Offset calculation: DSM creation failed"); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Generate the DSM */ + UA_StatusCode res = UA_DataSetReader_generateDataSetMessage(server, dsm, dataSetReader); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub RT Offset calculation: DataSetMessage generation failed"); + UA_DataSetMessage_clear(dsm); + UA_free(dsm); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Generate data set messages - Considering 1 DSM as max */ + UA_UInt16 *dsWriterIds = (UA_UInt16 *)UA_calloc(1, sizeof(UA_UInt16)); + if(!dsWriterIds) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub RT Offset calculation: DataSetWriterId creation failed"); + UA_DataSetMessage_clear(dsm); + UA_free(dsm); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + *dsWriterIds = dataSetReader->config.dataSetWriterId; + + UA_NetworkMessage *networkMessage = (UA_NetworkMessage *)UA_calloc(1, sizeof(UA_NetworkMessage)); + if(!networkMessage) { + UA_free(dsWriterIds); + UA_DataSetMessage_clear(dsm); + UA_free(dsm); + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub RT Offset calculation: Network message creation failed"); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + res = UA_DataSetReader_generateNetworkMessage(pubSubConnection, dataSetReader, dsm, + dsWriterIds, 1, networkMessage); + if(res != UA_STATUSCODE_GOOD) { + UA_free(networkMessage->payload.dataSetPayload.sizes); + UA_free(networkMessage); + UA_free(dsWriterIds); + UA_DataSetMessage_clear(dsm); + UA_free(dsm); + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub RT Offset calculation: NetworkMessage generation failed"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + memset(&dataSetReader->bufferedMessage, 0, sizeof(UA_NetworkMessageOffsetBuffer)); + dataSetReader->bufferedMessage.RTsubscriberEnabled = true; + + /* Fix the offsets necessary to decode */ + UA_NetworkMessage_calcSizeBinary(networkMessage, &dataSetReader->bufferedMessage); + dataSetReader->bufferedMessage.nm = networkMessage; + return UA_STATUSCODE_GOOD; } +UA_StatusCode +UA_Server_unfreezeReaderGroupConfiguration(UA_Server *server, + const UA_NodeId readerGroupId) { + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId); + if(!rg) + return UA_STATUSCODE_BADNOTFOUND; + + /* PubSubConnection freezeCounter-- */ + UA_NodeId pubSubConnectionId = rg->linkedConnection; + UA_PubSubConnection *pubSubConnection = + UA_PubSubConnection_findConnectionbyId(server, pubSubConnectionId); + pubSubConnection->configurationFreezeCounter--; + if(pubSubConnection->configurationFreezeCounter == 0){ + pubSubConnection->configurationFrozen = UA_FALSE; + } + + /* ReaderGroup unfreeze */ + rg->configurationFrozen = UA_FALSE; + + /* DataSetReader unfreeze */ + UA_DataSetReader *dataSetReader; + LIST_FOREACH(dataSetReader, &rg->readers, listEntry) { + dataSetReader->configurationFrozen = UA_FALSE; + } + + if(rg->config.rtLevel != UA_PUBSUB_RT_FIXED_SIZE) + return UA_STATUSCODE_GOOD; + + dataSetReader = LIST_FIRST(&rg->readers); + if(dataSetReader->bufferedMessage.offsetsSize > 0) { + for(size_t i = 0; i < dataSetReader->bufferedMessage.offsetsSize; i++) { + UA_NetworkMessageOffset *offset = &dataSetReader->bufferedMessage.offsets[i]; + if((offset->contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT) || + (offset->contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW)) { + UA_DataValue_delete(offset->offsetData.value.value); + } else if(offset->contentType == UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING) { + offset->offsetData.value.value->value.data = NULL; + UA_DataValue_delete(offset->offsetData.value.value); + } + } + UA_free(dataSetReader->bufferedMessage.offsets); + } + + if(dataSetReader->bufferedMessage.RTsubscriberEnabled && + dataSetReader->bufferedMessage.nm) { + UA_NetworkMessage_delete(dataSetReader->bufferedMessage.nm); + UA_free(dataSetReader->bufferedMessage.nm); + } + + return UA_STATUSCODE_GOOD; +} + +/* This triggers the collection and reception of NetworkMessages and the + * contained DataSetMessages. */ +void +UA_ReaderGroup_subscribeCallback(UA_Server *server, + UA_ReaderGroup *readerGroup) { + // TODO: feedback for debug-assert vs runtime-check + UA_assert(server); + UA_assert(readerGroup); + + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PubSub subscribe callback"); + + UA_PubSubConnection *connection = + UA_PubSubConnection_findConnectionbyId(server, readerGroup->linkedConnection); + if(!connection) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "SubscribeCallback(): Find linked connection failed"); + UA_ReaderGroup_setPubSubState(server, UA_PUBSUBSTATE_ERROR, readerGroup); + return; + } + + receiveBufferedNetworkMessage(server, readerGroup, connection); +} + +/* Add new subscribeCallback. The first execution is triggered directly after + * creation. */ +UA_StatusCode +UA_ReaderGroup_addSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(readerGroup->config.pubsubManagerCallback.addCustomCallback) + retval = readerGroup->config.pubsubManagerCallback. + addCustomCallback(server, readerGroup->identifier, + (UA_ServerCallback)UA_ReaderGroup_subscribeCallback, + readerGroup, readerGroup->config.subscribingInterval, + NULL, // TODO: Send base time from reader group config + // TODO: Send timer policy from reader group config + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, + &readerGroup->subscribeCallbackId); + else { + if(readerGroup->config.enableBlockingSocket == UA_TRUE) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "addSubscribeCallback() failed, blocking socket " + "functionality only supported in customcallback"); + return UA_STATUSCODE_BADNOTSUPPORTED; + } + + retval = UA_PubSubManager_addRepeatedCallback(server, + (UA_ServerCallback)UA_ReaderGroup_subscribeCallback, + readerGroup, readerGroup->config.subscribingInterval, + NULL, // TODO: Send base time from reader group config + // TODO: Send timer policy from reader group config + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, + &readerGroup->subscribeCallbackId); + } + + /* Run once after creation */ + /* When using blocking socket functionality, the server mechanism might get + * blocked. It is highly recommended to use custom callback when using + * blockingsocket. */ + if(readerGroup->config.enableBlockingSocket != UA_TRUE) + UA_ReaderGroup_subscribeCallback(server, readerGroup); + + return retval; +} + +void +UA_ReaderGroup_removeSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup) { + if(readerGroup->config.pubsubManagerCallback.removeCustomCallback) + readerGroup->config.pubsubManagerCallback. + removeCustomCallback(server, readerGroup->identifier, + readerGroup->subscribeCallbackId); + else + UA_PubSubManager_removeRepeatedPubSubCallback(server, + readerGroup->subscribeCallbackId); +} + #endif /* UA_ENABLE_PUBSUB */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_manager.c" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_manager.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -30899,6 +32540,7 @@ UA_Server_processNetworkMessage(UA_Server *server, UA_NetworkMessage *pMsg, #ifdef UA_ENABLE_PUBSUB /* conditional compilation */ + #define UA_DATETIMESTAMP_2000 125911584000000000 UA_StatusCode @@ -30907,11 +32549,11 @@ UA_Server_addPubSubConnection(UA_Server *server, UA_NodeId *connectionIdentifier) { /* Find the matching UA_PubSubTransportLayers */ UA_PubSubTransportLayer *tl = NULL; - for(size_t i = 0; i < server->config.pubsubTransportLayersSize; i++) { + for(size_t i = 0; i < server->config.pubSubConfig.transportLayersSize; i++) { if(connectionConfig && - UA_String_equal(&server->config.pubsubTransportLayers[i].transportProfileUri, + UA_String_equal(&server->config.pubSubConfig.transportLayers[i].transportProfileUri, &connectionConfig->transportProfileUri)) { - tl = &server->config.pubsubTransportLayers[i]; + tl = &server->config.pubSubConfig.transportLayers[i]; } } if(!tl) { @@ -30946,6 +32588,7 @@ UA_Server_addPubSubConnection(UA_Server *server, "PubSub Connection creation failed. Out of Memory."); return UA_STATUSCODE_BADOUTOFMEMORY; } + newConnectionsField->componentType = UA_PUBSUB_COMPONENT_CONNECTION; if (server->pubSubManager.connectionsSize != 0) TAILQ_INSERT_TAIL(&server->pubSubManager.connections, newConnectionsField, listEntry); else { @@ -30970,14 +32613,18 @@ UA_Server_addPubSubConnection(UA_Server *server, return UA_STATUSCODE_BADINTERNALERROR; } - UA_PubSubManager_generateUniqueNodeId(server, &newConnectionsField->identifier); +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + /* Internally createa a unique id */ + addPubSubConnectionRepresentation(server, newConnectionsField); +#else + /* Create a unique NodeId that does not correspond to a Node */ + UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, + &newConnectionsField->identifier); +#endif if(connectionIdentifier) UA_NodeId_copy(&newConnectionsField->identifier, connectionIdentifier); -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - addPubSubConnectionRepresentation(server, newConnectionsField); -#endif return UA_STATUSCODE_GOOD; } @@ -30999,8 +32646,30 @@ UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection) return UA_STATUSCODE_GOOD; } +UA_StatusCode +UA_PubSubConnection_regist(UA_Server *server, UA_NodeId *connectionIdentifier) { + UA_PubSubConnection *connection = + UA_PubSubConnection_findConnectionbyId(server, *connectionIdentifier); + if(!connection) + return UA_STATUSCODE_BADNOTFOUND; + + if(connection->isRegistered) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, "Connection already registered"); + return UA_STATUSCODE_GOOD; + } + + UA_StatusCode retval = connection->channel->regist(connection->channel, NULL, NULL); + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "register channel failed: 0x%" PRIx32 "!", retval); + + connection->isRegistered = UA_TRUE; + return retval; +} + UA_AddPublishedDataSetResult -UA_Server_addPublishedDataSet(UA_Server *server, const UA_PublishedDataSetConfig *publishedDataSetConfig, +UA_Server_addPublishedDataSet(UA_Server *server, + const UA_PublishedDataSetConfig *publishedDataSetConfig, UA_NodeId *pdsIdentifier) { UA_AddPublishedDataSetResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, 0, NULL, {0, 0}}; if(!publishedDataSetConfig){ @@ -31008,97 +32677,96 @@ UA_Server_addPublishedDataSet(UA_Server *server, const UA_PublishedDataSetConfig "PublishedDataSet creation failed. No config passed in."); return result; } + if(publishedDataSetConfig->publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){ UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "PublishedDataSet creation failed. Unsupported PublishedDataSet type."); return result; } - //deep copy the given connection config - UA_PublishedDataSetConfig tmpPublishedDataSetConfig; - memset(&tmpPublishedDataSetConfig, 0, sizeof(UA_PublishedDataSetConfig)); - if(UA_PublishedDataSetConfig_copy(publishedDataSetConfig, &tmpPublishedDataSetConfig) != UA_STATUSCODE_GOOD){ - UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, - "PublishedDataSet creation failed. Configuration copy failed."); - result.addResult = UA_STATUSCODE_BADINTERNALERROR; - return result; - } - //create new PDS and add to UA_PubSubManager - UA_PublishedDataSet *newPubSubDataSetField = (UA_PublishedDataSet *) - UA_calloc(1, sizeof(UA_PublishedDataSet)); - if(!newPubSubDataSetField) { - UA_PublishedDataSetConfig_clear(&tmpPublishedDataSetConfig); + + /* Create new PDS and add to UA_PubSubManager */ + UA_PublishedDataSet *newPDS = (UA_PublishedDataSet *) + UA_calloc(1, sizeof(UA_PublishedDataSet)); + if(!newPDS) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "PublishedDataSet creation failed. Out of Memory."); result.addResult = UA_STATUSCODE_BADOUTOFMEMORY; return result; } - memset(newPubSubDataSetField, 0, sizeof(UA_PublishedDataSet)); - TAILQ_INIT(&newPubSubDataSetField->fields); - newPubSubDataSetField->config = tmpPublishedDataSetConfig; + TAILQ_INIT(&newPDS->fields); - if (server->pubSubManager.publishedDataSetsSize != 0) - TAILQ_INSERT_TAIL(&server->pubSubManager.publishedDataSets, newPubSubDataSetField, listEntry); - else { - TAILQ_INIT(&server->pubSubManager.publishedDataSets); - TAILQ_INSERT_HEAD(&server->pubSubManager.publishedDataSets, newPubSubDataSetField, listEntry); - } - if(tmpPublishedDataSetConfig.publishedDataSetType == UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE){ - //parse template config and add fields (later PubSub batch) + UA_PublishedDataSetConfig *newConfig = &newPDS->config; + + /* Deep copy the given connection config */ + UA_StatusCode res = UA_PublishedDataSetConfig_copy(publishedDataSetConfig, newConfig); + if(res != UA_STATUSCODE_GOOD){ + UA_free(newPDS); + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "PublishedDataSet creation failed. Configuration copy failed."); + result.addResult = UA_STATUSCODE_BADINTERNALERROR; + return result; } - //generate unique nodeId - UA_PubSubManager_generateUniqueNodeId(server, &newPubSubDataSetField->identifier); - if(pdsIdentifier != NULL){ - UA_NodeId_copy(&newPubSubDataSetField->identifier, pdsIdentifier); + + /* TODO: Parse template config and add fields (later PubSub batch) */ + if(newConfig->publishedDataSetType == UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE) { } - result.addResult = UA_STATUSCODE_GOOD; - result.fieldAddResults = NULL; - result.fieldAddResultsSize = 0; + /* Fill the DataSetMetaData */ + result.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference(); + result.configurationVersion.minorVersion = UA_PubSubConfigurationVersionTimeDifference(); + switch(newConfig->publishedDataSetType) { + case UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE: + res = UA_STATUSCODE_BADNOTSUPPORTED; + break; + case UA_PUBSUB_DATASET_PUBLISHEDEVENTS: + res = UA_STATUSCODE_BADNOTSUPPORTED; + break; + case UA_PUBSUB_DATASET_PUBLISHEDITEMS: + newPDS->dataSetMetaData.configurationVersion.majorVersion = + UA_PubSubConfigurationVersionTimeDifference(); + newPDS->dataSetMetaData.configurationVersion.minorVersion = + UA_PubSubConfigurationVersionTimeDifference(); + newPDS->dataSetMetaData.description = UA_LOCALIZEDTEXT_ALLOC("", ""); + newPDS->dataSetMetaData.dataSetClassId = UA_GUID_NULL; + res = UA_String_copy(&newConfig->name, &newPDS->dataSetMetaData.name); + break; + case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE: + res = UA_DataSetMetaDataType_copy(&newConfig->config.itemsTemplate.metaData, + &newPDS->dataSetMetaData); + break; + default: + res = UA_STATUSCODE_BADINTERNALERROR; + } - //fill the DataSetMetaData - switch(tmpPublishedDataSetConfig.publishedDataSetType){ - case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE: - if(UA_DataSetMetaDataType_copy(&tmpPublishedDataSetConfig.config.itemsTemplate.metaData, - &newPubSubDataSetField->dataSetMetaData) != UA_STATUSCODE_GOOD){ - UA_Server_removeDataSetField(server, newPubSubDataSetField->identifier); - result.addResult = UA_STATUSCODE_BADINTERNALERROR; - } - break; - case UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE: - if(UA_DataSetMetaDataType_copy(&tmpPublishedDataSetConfig.config.eventTemplate.metaData, - &newPubSubDataSetField->dataSetMetaData) != UA_STATUSCODE_GOOD){ - UA_Server_removeDataSetField(server, newPubSubDataSetField->identifier); - result.addResult = UA_STATUSCODE_BADINTERNALERROR; - } - break; - case UA_PUBSUB_DATASET_PUBLISHEDEVENTS: - newPubSubDataSetField->dataSetMetaData.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference(); - newPubSubDataSetField->dataSetMetaData.configurationVersion.minorVersion = UA_PubSubConfigurationVersionTimeDifference(); - newPubSubDataSetField->dataSetMetaData.dataSetClassId = UA_GUID_NULL; - if(UA_String_copy(&tmpPublishedDataSetConfig.name, &newPubSubDataSetField->dataSetMetaData.name) != UA_STATUSCODE_GOOD){ - UA_Server_removeDataSetField(server, newPubSubDataSetField->identifier); - result.addResult = UA_STATUSCODE_BADINTERNALERROR; - } - newPubSubDataSetField->dataSetMetaData.description = UA_LOCALIZEDTEXT_ALLOC("", ""); - break; - case UA_PUBSUB_DATASET_PUBLISHEDITEMS: - newPubSubDataSetField->dataSetMetaData.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference(); - newPubSubDataSetField->dataSetMetaData.configurationVersion.minorVersion = UA_PubSubConfigurationVersionTimeDifference(); - if(UA_String_copy(&tmpPublishedDataSetConfig.name, &newPubSubDataSetField->dataSetMetaData.name) != UA_STATUSCODE_GOOD){ - UA_Server_removeDataSetField(server, newPubSubDataSetField->identifier); - result.addResult = UA_STATUSCODE_BADINTERNALERROR; - } - newPubSubDataSetField->dataSetMetaData.description = UA_LOCALIZEDTEXT_ALLOC("", ""); - newPubSubDataSetField->dataSetMetaData.dataSetClassId = UA_GUID_NULL; - break; + /* Abort? */ + result.addResult = res; + if(result.addResult != UA_STATUSCODE_GOOD) { + UA_PublishedDataSetConfig_clear(newConfig); + UA_free(newPDS); + return result; } + /* Insert into the queue of the manager */ + if(server->pubSubManager.publishedDataSetsSize != 0) { + TAILQ_INSERT_TAIL(&server->pubSubManager.publishedDataSets, + newPDS, listEntry); + } else { + TAILQ_INIT(&server->pubSubManager.publishedDataSets); + TAILQ_INSERT_HEAD(&server->pubSubManager.publishedDataSets, + newPDS, listEntry); + } server->pubSubManager.publishedDataSetsSize++; - result.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference(); - result.configurationVersion.minorVersion = UA_PubSubConfigurationVersionTimeDifference(); + #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL - addPublishedDataItemsRepresentation(server, newPubSubDataSetField); + /* Create representation and unique id */ + addPublishedDataItemsRepresentation(server, newPDS); +#else + /* Generate unique nodeId */ + UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, &newPDS->identifier); #endif + if(pdsIdentifier) + UA_NodeId_copy(&newPDS->identifier, pdsIdentifier); + return result; } @@ -31109,7 +32777,7 @@ UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pds) { if(!publishedDataSet){ return UA_STATUSCODE_BADNOTFOUND; } - if(publishedDataSet->config.configurationFrozen){ + if(publishedDataSet->configurationFrozen){ UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Remove PublishedDataSet failed. PublishedDataSet is frozen."); return UA_STATUSCODE_BADCONFIGURATIONERROR; @@ -31142,19 +32810,29 @@ UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pds) { /* Calculate the time difference between current time and UTC (00:00) on January * 1, 2000. */ UA_UInt32 -UA_PubSubConfigurationVersionTimeDifference() { +UA_PubSubConfigurationVersionTimeDifference(void) { UA_UInt32 timeDiffSince2000 = (UA_UInt32) (UA_DateTime_now() - UA_DATETIMESTAMP_2000); return timeDiffSince2000; } /* Generate a new unique NodeId. This NodeId will be used for the information * model representation of PubSub entities. */ +#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL void -UA_PubSubManager_generateUniqueNodeId(UA_Server *server, UA_NodeId *nodeId) { - UA_NodeId newNodeId = UA_NODEID_NUMERIC(0, 0); - UA_Node *newNode = UA_NODESTORE_NEW(server, UA_NODECLASS_OBJECT); - UA_NODESTORE_INSERT(server, newNode, &newNodeId); - UA_NodeId_copy(&newNodeId, nodeId); +UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId) { + *nodeId = UA_NODEID_NUMERIC(1, ++psm->uniqueIdCount); +} +#endif + +UA_Guid +UA_PubSubManager_generateUniqueGuid(UA_Server *server) { + while(true) { + UA_NodeId testId = UA_NODEID_GUID(1, UA_Guid_random()); + const UA_Node *testNode = UA_NODESTORE_GET(server, &testId); + if(!testNode) + return testId.identifier.guid; + UA_NODESTORE_RELEASE(server, testNode); + } } /* Delete the current PubSub configuration including all nested members. This @@ -31176,9 +32854,9 @@ UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager) { } //free the currently configured transport layers - if (server->config.pubsubTransportLayersSize > 0) { - UA_free(server->config.pubsubTransportLayers); - server->config.pubsubTransportLayersSize = 0; + if(server->config.pubSubConfig.transportLayersSize > 0) { + UA_free(server->config.pubSubConfig.transportLayers); + server->config.pubSubConfig.transportLayersSize = 0; } //remove Connections and WriterGroups @@ -31196,22 +32874,21 @@ UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager) { /* PubSub Jobs abstraction */ /***********************************/ -#ifndef UA_ENABLE_PUBSUB_CUSTOM_PUBLISH_HANDLING - -/* If UA_ENABLE_PUBSUB_CUSTOM_PUBLISH_HANDLING is enabled, a custom callback - * management must be linked to the application */ +/* Default Timer based PubSub Callbacks */ UA_StatusCode UA_PubSubManager_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, - void *data, UA_Double interval_ms, UA_UInt64 *callbackId) { + void *data, UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) { return UA_Timer_addRepeatedCallback(&server->timer, (UA_ApplicationCallback)callback, - server, data, interval_ms, callbackId); + server, data, interval_ms, baseTime, timerPolicy, callbackId); } UA_StatusCode -UA_PubSubManager_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, - UA_Double interval_ms) { - return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval_ms); +UA_PubSubManager_changeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy) { + return UA_Timer_changeRepeatedCallback(&server->timer, callbackId, interval_ms, baseTime, timerPolicy); } void @@ -31219,65 +32896,264 @@ UA_PubSubManager_removeRepeatedPubSubCallback(UA_Server *server, UA_UInt64 callb UA_Timer_removeCallback(&server->timer, callbackId); } -#endif /* UA_ENABLE_PUBSUB_CUSTOM_PUBLISH_HANDLING */ + +#ifdef UA_ENABLE_PUBSUB_MONITORING + +static UA_StatusCode +UA_PubSubComponent_createMonitoring(UA_Server *server, UA_NodeId Id, UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data, UA_ServerCallback callback) { + + if ((!server) || (!data)) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error UA_PubSubComponent_createMonitoring(): " + "null pointer param"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + UA_StatusCode ret = UA_STATUSCODE_GOOD; + switch (eComponentType) { + case UA_PUBSUB_COMPONENT_DATASETREADER: { + UA_DataSetReader *reader = (UA_DataSetReader*) data; + switch (eMonitoringType) { + case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_PubSubComponent_createMonitoring(): DataSetReader '%.*s' " + "- MessageReceiveTimeout", (UA_Int32) reader->config.name.length, reader->config.name.data); + reader->msgRcvTimeoutTimerCallback = callback; + break; + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_PubSubComponent_createMonitoring(): DataSetReader '%.*s' " + "DataSetReader does not support timeout type '%i'", (UA_Int32) reader->config.name.length, reader->config.name.data, + eMonitoringType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_createMonitoring(): PubSub component type '%i' is not supported", eComponentType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + return ret; +} + +static UA_StatusCode +UA_PubSubComponent_startMonitoring(UA_Server *server, UA_NodeId Id, UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data) { + + if ((!server) || (!data)) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error UA_PubSubComponent_startMonitoring(): " + "null pointer param"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + UA_StatusCode ret = UA_STATUSCODE_GOOD; + switch (eComponentType) { + case UA_PUBSUB_COMPONENT_DATASETREADER: { + UA_DataSetReader *reader = (UA_DataSetReader*) data; + switch (eMonitoringType) { + case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: { + /* use a timed callback, because one notification is enough, + we assume that MessageReceiveTimeout configuration is in [ms], we do not handle or check fractions */ + UA_UInt64 interval = (UA_UInt64)(reader->config.messageReceiveTimeout * UA_DATETIME_MSEC); + ret = UA_Timer_addTimedCallback(&server->timer, (UA_ApplicationCallback) reader->msgRcvTimeoutTimerCallback, + server, reader, UA_DateTime_nowMonotonic() + (UA_DateTime) interval, &(reader->msgRcvTimeoutTimerId)); + if (ret == UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_PubSubComponent_startMonitoring(): DataSetReader '%.*s'- MessageReceiveTimeout: MessageReceiveTimeout = '%f' " + "Timer Id = '%u'", (UA_Int32) reader->config.name.length, reader->config.name.data, + reader->config.messageReceiveTimeout, (UA_UInt32) reader->msgRcvTimeoutTimerId); + } else { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_startMonitoring(): DataSetReader '%.*s' - MessageReceiveTimeout: start timer failed", + (UA_Int32) reader->config.name.length, reader->config.name.data); + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_PubSubComponent_startMonitoring(): DataSetReader '%.*s' " + "DataSetReader does not support timeout type '%i'", (UA_Int32) reader->config.name.length, reader->config.name.data, + eMonitoringType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_startMonitoring(): PubSub component type '%i' is not supported", eComponentType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + return ret; +} + +static UA_StatusCode +UA_PubSubComponent_stopMonitoring(UA_Server *server, UA_NodeId Id, UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data) { + + if ((!server) || (!data)) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error UA_PubSubComponent_stopMonitoring(): " + "null pointer param"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + UA_StatusCode ret = UA_STATUSCODE_GOOD; + switch (eComponentType) { + case UA_PUBSUB_COMPONENT_DATASETREADER: { + UA_DataSetReader *reader = (UA_DataSetReader*) data; + switch (eMonitoringType) { + case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: { + UA_Timer_removeCallback(&server->timer, reader->msgRcvTimeoutTimerId); + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_PubSubComponent_stopMonitoring(): DataSetReader '%.*s' - MessageReceiveTimeout: MessageReceiveTimeout = '%f' " + "Timer Id = '%u'", (UA_Int32) reader->config.name.length, reader->config.name.data, + reader->config.messageReceiveTimeout, (UA_UInt32) reader->msgRcvTimeoutTimerId); + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_PubSubComponent_stopMonitoring(): DataSetReader '%.*s' " + "DataSetReader does not support timeout type '%i'", (UA_Int32) reader->config.name.length, reader->config.name.data, + eMonitoringType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_stopMonitoring(): PubSub component type '%i' is not supported", eComponentType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + return ret; +} + +static UA_StatusCode +UA_PubSubComponent_updateMonitoringInterval(UA_Server *server, UA_NodeId Id, UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data) +{ + if ((!server) || (!data)) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error UA_PubSubComponent_updateMonitoringInterval(): " + "null pointer param"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + UA_StatusCode ret = UA_STATUSCODE_GOOD; + switch (eComponentType) { + case UA_PUBSUB_COMPONENT_DATASETREADER: { + UA_DataSetReader *reader = (UA_DataSetReader*) data; + switch (eMonitoringType) { + case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: { + ret = UA_Timer_changeRepeatedCallback(&server->timer, reader->msgRcvTimeoutTimerId, + reader->config.messageReceiveTimeout, NULL, + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME); + if (ret == UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_PubSubComponent_updateMonitoringInterval(): DataSetReader '%.*s' - MessageReceiveTimeout: new MessageReceiveTimeout = '%f' " + "Timer Id = '%u'", (UA_Int32) reader->config.name.length, reader->config.name.data, + reader->config.messageReceiveTimeout, (UA_UInt32) reader->msgRcvTimeoutTimerId); + } else { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_updateMonitoringInterval(): DataSetReader '%.*s': update timer interval failed", + (UA_Int32) reader->config.name.length, reader->config.name.data); + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_PubSubComponent_createMonitoring(): DataSetReader '%.*s' " + "DataSetReader does not support timeout type '%i'", (UA_Int32) reader->config.name.length, reader->config.name.data, + eMonitoringType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_updateMonitoringInterval(): PubSub component type '%i' is not supported", eComponentType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + return ret; +} + +static UA_StatusCode +UA_PubSubComponent_deleteMonitoring(UA_Server *server, UA_NodeId Id, UA_PubSubComponentEnumType eComponentType, + UA_PubSubMonitoringType eMonitoringType, void *data) { + + if ((!server) || (!data)) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Error UA_PubSubComponent_deleteMonitoring(): " + "null pointer param"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + UA_StatusCode ret = UA_STATUSCODE_GOOD; + switch (eComponentType) { + case UA_PUBSUB_COMPONENT_DATASETREADER: { + UA_DataSetReader *reader = (UA_DataSetReader*) data; + switch (eMonitoringType) { + case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_PubSubComponent_deleteMonitoring(): DataSetReader '%.*s' - MessageReceiveTimeout: Timer Id = '%u'", + (UA_Int32) reader->config.name.length, reader->config.name.data, (UA_UInt32) reader->msgRcvTimeoutTimerId); + break; + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "UA_PubSubComponent_deleteMonitoring(): DataSetReader '%.*s' " + "DataSetReader does not support timeout type '%i'", (UA_Int32) reader->config.name.length, reader->config.name.data, + eMonitoringType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + break; + } + default: + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Error UA_PubSubComponent_deleteMonitoring(): PubSub component type '%i' is not supported", eComponentType); + ret = UA_STATUSCODE_BADNOTSUPPORTED; + break; + } + return ret; +} + +UA_StatusCode +UA_PubSubManager_setDefaultMonitoringCallbacks(UA_PubSubMonitoringInterface *monitoringInterface) { + if (monitoringInterface == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + monitoringInterface->createMonitoring = UA_PubSubComponent_createMonitoring; + monitoringInterface->startMonitoring = UA_PubSubComponent_startMonitoring; + monitoringInterface->stopMonitoring = UA_PubSubComponent_stopMonitoring; + monitoringInterface->updateMonitoringInterval = UA_PubSubComponent_updateMonitoringInterval; + monitoringInterface->deleteMonitoring = UA_PubSubComponent_deleteMonitoring; + return UA_STATUSCODE_GOOD; +} + +#endif /* UA_ENABLE_PUBSUB_MONITORING */ #endif /* UA_ENABLE_PUBSUB */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/pubsub/ua_pubsub_ns0.c" ***********************************/ +/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner) - * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2019-2021 Kalycito Infotech Private Limited + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG */ +#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG +#endif + #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */ -typedef struct{ +typedef struct { UA_NodeId parentNodeId; UA_UInt32 parentClassifier; UA_UInt32 elementClassiefier; } UA_NodePropertyContext; -//Prototypes -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS -static UA_StatusCode addWriterGroupAction(UA_Server *server, - const UA_NodeId *sessionId, void *sessionHandle, - const UA_NodeId *methodId, void *methodContext, - const UA_NodeId *objectId, void *objectContext, - size_t inputSize, const UA_Variant *input, - size_t outputSize, UA_Variant *output); -static UA_StatusCode removeGroupAction(UA_Server *server, - const UA_NodeId *sessionId, void *sessionHandle, - const UA_NodeId *methodId, void *methodContext, - const UA_NodeId *objectId, void *objectContext, - size_t inputSize, const UA_Variant *input, - size_t outputSize, UA_Variant *output); -static UA_StatusCode addDataSetWriterAction(UA_Server *server, - const UA_NodeId *sessionId, void *sessionHandle, - const UA_NodeId *methodId, void *methodContext, - const UA_NodeId *objectId, void *objectContext, - size_t inputSize, const UA_Variant *input, - size_t outputSize, UA_Variant *output); - -#endif - -static UA_StatusCode -addPubSubObjectNode(UA_Server *server, char* name, UA_UInt32 objectid, - UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) { - UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; - object_attr.displayName = UA_LOCALIZEDTEXT("", name); - return UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(0, objectid), - UA_NODEID_NUMERIC(0, parentid), - UA_NODEID_NUMERIC(0, referenceid), - UA_QUALIFIEDNAME(0, name), - UA_NODEID_NUMERIC(0, type_id), - object_attr, NULL, NULL); -} - static UA_StatusCode writePubSubNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, size_t length, const UA_DataType *type) { @@ -31302,16 +33178,16 @@ findSingleChildNode(UA_Server *server, UA_QualifiedName targetName, bp.startingNode = startingNode; bp.relativePath.elementsSize = 1; bp.relativePath.elements = &rpe; - UA_BrowsePathResult bpr = - UA_Server_translateBrowsePathToNodeIds(server, &bp); + UA_BrowsePathResult bpr = UA_Server_translateBrowsePathToNodeIds(server, &bp); if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) return UA_NODEID_NULL; - if(UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId) != UA_STATUSCODE_GOOD){ - UA_BrowsePathResult_deleteMembers(&bpr); + UA_StatusCode res = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId); + if(res != UA_STATUSCODE_GOOD){ + UA_BrowsePathResult_clear(&bpr); return UA_NODEID_NULL; } - UA_BrowsePathResult_deleteMembers(&bpr); + UA_BrowsePathResult_clear(&bpr); return resultNodeId; } @@ -31344,6 +33220,22 @@ onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, } break; } + case UA_NS0ID_DATASETREADERTYPE: { + UA_DataSetReader *dataSetReader = UA_ReaderGroup_findDSRbyId(server, *myNodeId); + if(!dataSetReader) + return; + + switch(nodeContext->elementClassiefier) { + case UA_NS0ID_DATASETREADERTYPE_PUBLISHERID: + UA_Variant_setScalar(&value, dataSetReader->config.publisherId.data, + dataSetReader->config.publisherId.type); + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Read error! Unknown property."); + } + break; + } case UA_NS0ID_WRITERGROUPTYPE: { UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, *myNodeId); if(!writerGroup) @@ -31359,6 +33251,22 @@ onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, } break; } + case UA_NS0ID_DATASETWRITERTYPE: { + UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, *myNodeId); + if(!dataSetWriter) + return; + + switch(nodeContext->elementClassiefier) { + case UA_NS0ID_DATASETWRITERTYPE_DATASETWRITERID: + UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetWriterId, + &UA_TYPES[UA_TYPES_UINT16]); + break; + default: + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Read error! Unknown property."); + } + break; + } case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: { UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId); if(!publishedDataSet) @@ -31445,60 +33353,340 @@ addVariableValueSource(UA_Server *server, UA_ValueCallback valueCallback, return UA_Server_setVariableNode_valueCallback(server, node, valueCallback); } +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS +static UA_StatusCode +addPubSubConnectionConfig(UA_Server *server, UA_PubSubConnectionDataType *pubsubConnectionDataType, + UA_NodeId *connectionId){ + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_NetworkAddressUrlDataType networkAddressUrlDataType; + memset(&networkAddressUrlDataType, 0, sizeof(networkAddressUrlDataType)); + UA_ExtensionObject eo = pubsubConnectionDataType->address; + if(eo.encoding == UA_EXTENSIONOBJECT_DECODED){ + if(eo.content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]){ + if(UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *) eo.content.decoded.data, + &networkAddressUrlDataType) != UA_STATUSCODE_GOOD){ + return UA_STATUSCODE_BADOUTOFMEMORY; + } + } + } + + UA_PubSubConnectionConfig connectionConfig; + memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); + connectionConfig.transportProfileUri = pubsubConnectionDataType->transportProfileUri; + connectionConfig.name = pubsubConnectionDataType->name; + //TODO set real connection state + connectionConfig.enabled = pubsubConnectionDataType->enabled; + //connectionConfig.enabled = pubSubConnectionDataType.enabled; + UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrlDataType, + &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); + if(pubsubConnectionDataType->publisherId.type == &UA_TYPES[UA_TYPES_UINT32]){ + connectionConfig.publisherId.numeric = * ((UA_UInt32 *) pubsubConnectionDataType->publisherId.data); + } else if(pubsubConnectionDataType->publisherId.type == &UA_TYPES[UA_TYPES_STRING]){ + connectionConfig.publisherIdType = UA_PUBSUB_PUBLISHERID_STRING; + UA_String_copy((UA_String *) pubsubConnectionDataType->publisherId.data, &connectionConfig.publisherId.string); + } else { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Unsupported PublisherId Type used."); + //TODO what's the best default behaviour here? + connectionConfig.publisherId.numeric = 0; + } + + retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, connectionId); + UA_NetworkAddressUrlDataType_clear(&networkAddressUrlDataType); + return retVal; +} + +/** + * **WriterGroup handling** + * + * The WriterGroup (WG) is part of the connection and contains the primary + * configuration parameters for the message creation. */ +static UA_StatusCode +addWriterGroupConfig(UA_Server *server, UA_NodeId connectionId, + UA_WriterGroupDataType *writerGroupDataType, UA_NodeId *writerGroupId){ + /* Now we create a new WriterGroupConfig and add the group to the existing + * PubSubConnection. */ + UA_WriterGroupConfig writerGroupConfig; + memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig)); + writerGroupConfig.name = writerGroupDataType->name; + writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval; + writerGroupConfig.enabled = writerGroupDataType->enabled; + writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId; + //TODO remove hard coded UADP + writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP; + writerGroupConfig.priority = writerGroupDataType->priority; + + UA_UadpWriterGroupMessageDataType writerGroupMessage; + UA_ExtensionObject *eoWG = &writerGroupDataType->messageSettings; + if(eoWG->encoding == UA_EXTENSIONOBJECT_DECODED){ + writerGroupConfig.messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED; + if(eoWG->content.decoded.type == &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]){ + if(UA_UadpWriterGroupMessageDataType_copy((UA_UadpWriterGroupMessageDataType *) eoWG->content.decoded.data, + &writerGroupMessage) != UA_STATUSCODE_GOOD){ + return UA_STATUSCODE_BADOUTOFMEMORY; + } + writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]; + writerGroupConfig.messageSettings.content.decoded.data = &writerGroupMessage; + } + } + + return UA_Server_addWriterGroup(server, connectionId, &writerGroupConfig, writerGroupId); +} + +/** + * **DataSetWriter handling** + * + * A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is + * linked to exactly one PDS and contains additional informations for the + * message generation. */ +static UA_StatusCode +addDataSetWriterConfig(UA_Server *server, const UA_NodeId *writerGroupId, + UA_DataSetWriterDataType *dataSetWriterDataType, + UA_NodeId *dataSetWriterId) { + UA_NodeId publishedDataSetId = UA_NODEID_NULL; + UA_PublishedDataSet *tmpPDS; + TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry){ + if(UA_String_equal(&dataSetWriterDataType->dataSetName, &tmpPDS->config.name)) { + publishedDataSetId = tmpPDS->identifier; + break; + } + } + + if(UA_NodeId_isNull(&publishedDataSetId)) + return UA_STATUSCODE_BADPARENTNODEIDINVALID; + + /* We need now a DataSetWriter within the WriterGroup. This means we must + * create a new DataSetWriterConfig and add call the addWriterGroup function. */ + UA_DataSetWriterConfig dataSetWriterConfig; + memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig)); + dataSetWriterConfig.name = dataSetWriterDataType->name; + dataSetWriterConfig.dataSetWriterId = dataSetWriterDataType->dataSetWriterId; + dataSetWriterConfig.keyFrameCount = dataSetWriterDataType->keyFrameCount; + dataSetWriterConfig.dataSetFieldContentMask = dataSetWriterDataType->dataSetFieldContentMask; + return UA_Server_addDataSetWriter(server, *writerGroupId, publishedDataSetId, + &dataSetWriterConfig, dataSetWriterId); +} + +/** + * **ReaderGroup** + * + * ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are + * created within a PubSubConnection and automatically deleted if the connection + * is removed. All network message related filters are only available in the DataSetReader. */ +/* Add ReaderGroup to the created connection */ +static UA_StatusCode +addReaderGroupConfig(UA_Server *server, UA_NodeId connectionId, + UA_ReaderGroupDataType *readerGroupDataType, + UA_NodeId *readerGroupId) { + UA_ReaderGroupConfig readerGroupConfig; + memset(&readerGroupConfig, 0, sizeof(UA_ReaderGroupConfig)); + readerGroupConfig.name = readerGroupDataType->name; + return UA_Server_addReaderGroup(server, connectionId, + &readerGroupConfig, readerGroupId); +} + +/** + * **SubscribedDataSet** + * + * Set SubscribedDataSet type to TargetVariables data type. + * Add subscribedvariables to the DataSetReader */ +static UA_StatusCode +addSubscribedVariables(UA_Server *server, UA_NodeId dataSetReaderId, + UA_DataSetReaderDataType *dataSetReaderDataType, + UA_DataSetMetaDataType *pMetaData) { + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_TargetVariablesDataType targetVars; + UA_ExtensionObject *eoTargetVar = &dataSetReaderDataType->subscribedDataSet; + if(eoTargetVar->encoding == UA_EXTENSIONOBJECT_DECODED){ + if(eoTargetVar->content.decoded.type == &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]){ + if(UA_TargetVariablesDataType_copy((UA_TargetVariablesDataType *) eoTargetVar->content.decoded.data, + &targetVars) != UA_STATUSCODE_GOOD){ + return UA_STATUSCODE_BADOUTOFMEMORY; + } + } + UA_NodeId folderId; + UA_String folderName = pMetaData->name; + UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; + UA_QualifiedName folderBrowseName; + if(folderName.length > 0) { + oAttr.displayName.locale = UA_STRING(""); + oAttr.displayName.text = folderName; + folderBrowseName.namespaceIndex = 1; + folderBrowseName.name = folderName; + } else { + oAttr.displayName = UA_LOCALIZEDTEXT("", "Subscribed Variables"); + folderBrowseName = UA_QUALIFIEDNAME(1, "Subscribed Variables"); + } + + UA_Server_addObjectNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER), + UA_NODEID_NUMERIC (0, UA_NS0ID_ORGANIZES), + folderBrowseName, UA_NODEID_NUMERIC (0, + UA_NS0ID_BASEOBJECTTYPE), oAttr, NULL, &folderId); + /** + * **TargetVariables** + * + * The SubscribedDataSet option TargetVariables defines a list of Variable mappings between + * received DataSet fields and target Variables in the Subscriber AddressSpace. + * The values subscribed from the Publisher are updated in the value field of these variables */ + /* Create the TargetVariables with respect to DataSetMetaData fields */ + UA_FieldTargetVariable *targetVarsData = (UA_FieldTargetVariable *) + UA_calloc(targetVars.targetVariablesSize, sizeof(UA_FieldTargetVariable)); + for(size_t i = 0; i < targetVars.targetVariablesSize; i++) { + /* Variable to subscribe data */ + UA_VariableAttributes vAttr = UA_VariableAttributes_default; + UA_LocalizedText_copy(&pMetaData->fields[i].description, + &vAttr.description); + vAttr.displayName.locale = UA_STRING(""); + vAttr.displayName.text = pMetaData->fields[i].name; + vAttr.dataType = pMetaData->fields[i].dataType; + + UA_NodeId newNode; + retVal |= UA_Server_addVariableNode(server, targetVars.targetVariables[i].targetNodeId, + folderId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(1, (char *)pMetaData->fields[i].name.data), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + vAttr, NULL, &newNode); + + /* For creating Targetvariables */ + UA_FieldTargetDataType_init(&targetVarsData[i].targetVariable); + targetVarsData[i].targetVariable.attributeId = targetVars.targetVariables[i].attributeId; + targetVarsData[i].targetVariable.targetNodeId = newNode; + } + retVal = UA_Server_DataSetReader_createTargetVariables(server, dataSetReaderId, + targetVars.targetVariablesSize, targetVarsData); + for(size_t j = 0; j < targetVars.targetVariablesSize; j++) + UA_FieldTargetDataType_clear(&targetVarsData[j].targetVariable); + UA_free(targetVarsData); + } + + return retVal; +} + +/** + * **DataSetReader** + * + * DataSetReader can receive NetworkMessages with the DataSetMessage + * of interest sent by the Publisher. DataSetReader provides + * the configuration necessary to receive and process DataSetMessages + * on the Subscriber side. DataSetReader must be linked with a + * SubscribedDataSet and be contained within a ReaderGroup. */ +/* Add DataSetReader to the ReaderGroup */ +static UA_StatusCode +addDataSetReaderConfig(UA_Server *server, UA_NodeId readerGroupId, + UA_DataSetReaderDataType *dataSetReaderDataType, + UA_NodeId *dataSetReaderId) { + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_DataSetReaderConfig readerConfig; + memset (&readerConfig, 0, sizeof(UA_DataSetReaderConfig)); + readerConfig.name = dataSetReaderDataType->name; + /* Parameters to filter which DataSetMessage has to be processed + * by the DataSetReader */ + if(dataSetReaderDataType->publisherId.type == &UA_TYPES[UA_TYPES_STRING]){ + UA_String publisherIdentifier; + readerConfig.publisherId.type = &UA_TYPES[UA_TYPES_STRING]; + UA_String_copy((UA_String *) dataSetReaderDataType->publisherId.data, &publisherIdentifier); + readerConfig.publisherId.data = &publisherIdentifier; + } else { + UA_UInt16 publisherIdentifier = *(UA_UInt16*)dataSetReaderDataType->publisherId.data; + readerConfig.publisherId.type = &UA_TYPES[UA_TYPES_UINT16]; + readerConfig.publisherId.data = &publisherIdentifier; + } + + readerConfig.writerGroupId = dataSetReaderDataType->writerGroupId; + readerConfig.dataSetWriterId = dataSetReaderDataType->dataSetWriterId; + + /* Setting up Meta data configuration in DataSetReader */ + UA_DataSetMetaDataType *pMetaData; + pMetaData = &readerConfig.dataSetMetaData; + UA_DataSetMetaDataType_init (pMetaData); + pMetaData->name = dataSetReaderDataType->dataSetMetaData.name; + pMetaData->fieldsSize = dataSetReaderDataType->dataSetMetaData.fieldsSize; + pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize, + &UA_TYPES[UA_TYPES_FIELDMETADATA]); + for(size_t i = 0; i < pMetaData->fieldsSize; i++){ + UA_FieldMetaData_init (&pMetaData->fields[i]); + UA_NodeId_copy (&dataSetReaderDataType->dataSetMetaData.fields[i].dataType, + &pMetaData->fields[i].dataType); + pMetaData->fields[i].builtInType = dataSetReaderDataType->dataSetMetaData.fields[i].builtInType; + pMetaData->fields[i].name = dataSetReaderDataType->dataSetMetaData.fields[i].name; + pMetaData->fields[i].valueRank = dataSetReaderDataType->dataSetMetaData.fields[i].valueRank; + } + + retVal |= UA_Server_addDataSetReader(server, readerGroupId, &readerConfig, + dataSetReaderId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_free(pMetaData->fields); + return retVal; + } + + retVal |= addSubscribedVariables(server, *dataSetReaderId, dataSetReaderDataType, pMetaData); + UA_free(pMetaData->fields); + return retVal; +} +#endif + /*************************************************/ /* PubSubConnection */ /*************************************************/ UA_StatusCode -addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){ +addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; if(connection->config->name.length > 512) return UA_STATUSCODE_BADOUTOFMEMORY; - UA_STACKARRAY(char, connectionName, sizeof(char) * connection->config->name.length +1); + char connectionName[513]; memcpy(connectionName, connection->config->name.data, connection->config->name.length); connectionName[connection->config->name.length] = '\0'; - //This code block must use a lock - UA_NODESTORE_REMOVE(server, &connection->identifier); - UA_NodeId pubSubConnectionNodeId; + UA_ObjectAttributes attr = UA_ObjectAttributes_default; - attr.displayName = UA_LOCALIZEDTEXT("de-DE", connectionName); + attr.displayName = UA_LOCALIZEDTEXT("", connectionName); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, - UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric), + UA_NODEID_NUMERIC(1, 0), /* Generate a new id */ UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION), UA_QUALIFIEDNAME(0, connectionName), UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), - (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], - NULL, &pubSubConnectionNodeId); - addPubSubObjectNode(server, "Address", connection->identifier.identifier.numeric+1, - pubSubConnectionNodeId.identifier.numeric, UA_NS0ID_HASCOMPONENT, - UA_NS0ID_NETWORKADDRESSURLTYPE); - UA_Server_addNode_finish(server, pubSubConnectionNodeId); - //End lock zone - - UA_NodeId addressNode, urlNode, interfaceNode, publisherIdNode, connectionPropertieNode, transportProfileUri; + (const UA_NodeAttributes*)&attr, + &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], + NULL, &connection->identifier); + + attr.displayName = UA_LOCALIZEDTEXT("", "Address"); + retVal |= UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), + connection->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(0, "Address"), + UA_NODEID_NUMERIC(0, UA_NS0ID_NETWORKADDRESSURLTYPE), + attr, NULL, NULL); + + UA_Server_addNode_finish(server, connection->identifier); + + UA_NodeId addressNode, urlNode, interfaceNode, publisherIdNode, + connectionPropertieNode, transportProfileUri; addressNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), - UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric)); + connection->identifier); urlNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode); + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + addressNode); interfaceNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode); + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + addressNode); publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric)); - connectionPropertieNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric)); - transportProfileUri = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), - UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric)); - - if(UA_NodeId_equal(&addressNode, &UA_NODEID_NULL) || - UA_NodeId_equal(&urlNode, &UA_NODEID_NULL) || - UA_NodeId_equal(&interfaceNode, &UA_NODEID_NULL) || - UA_NodeId_equal(&publisherIdNode, &UA_NODEID_NULL) || - UA_NodeId_equal(&connectionPropertieNode, &UA_NODEID_NULL) || - UA_NodeId_equal(&transportProfileUri, &UA_NODEID_NULL)) { + connection->identifier); + connectionPropertieNode = findSingleChildNode(server, + UA_QUALIFIEDNAME(0, "ConnectionProperties"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + connection->identifier); + transportProfileUri = findSingleChildNode(server, + UA_QUALIFIEDNAME(0, "TransportProfileUri"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + connection->identifier); + + if(UA_NodeId_isNull(&addressNode) || UA_NodeId_isNull(&urlNode) || + UA_NodeId_isNull(&interfaceNode) || UA_NodeId_isNull(&publisherIdNode) || + UA_NodeId_isNull(&connectionPropertieNode) || + UA_NodeId_isNull(&transportProfileUri)) { return UA_STATUSCODE_BADNOTFOUND; } @@ -31507,35 +33695,45 @@ addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connec connection->config->connectionPropertiesSize, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); - UA_NetworkAddressUrlDataType *networkAddressUrlDataType = ((UA_NetworkAddressUrlDataType *) connection->config->address.data); + UA_NetworkAddressUrlDataType *networkAddressUrlDataType = + ((UA_NetworkAddressUrlDataType*)connection->config->address.data); UA_Variant value; UA_Variant_init(&value); - UA_Variant_setScalar(&value, &networkAddressUrlDataType->url, &UA_TYPES[UA_TYPES_STRING]); + UA_Variant_setScalar(&value, &networkAddressUrlDataType->url, + &UA_TYPES[UA_TYPES_STRING]); UA_Server_writeValue(server, urlNode, value); - UA_Variant_setScalar(&value, &networkAddressUrlDataType->networkInterface, &UA_TYPES[UA_TYPES_STRING]); + UA_Variant_setScalar(&value, &networkAddressUrlDataType->networkInterface, + &UA_TYPES[UA_TYPES_STRING]); UA_Server_writeValue(server, interfaceNode, value); - UA_Variant_setScalar(&value, &connection->config->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]); + UA_Variant_setScalar(&value, &connection->config->transportProfileUri, + &UA_TYPES[UA_TYPES_STRING]); UA_Server_writeValue(server, transportProfileUri, value); - UA_NodePropertyContext *connectionPublisherIdContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext)); + UA_NodePropertyContext *connectionPublisherIdContext = (UA_NodePropertyContext *) + UA_malloc(sizeof(UA_NodePropertyContext)); connectionPublisherIdContext->parentNodeId = connection->identifier; connectionPublisherIdContext->parentClassifier = UA_NS0ID_PUBSUBCONNECTIONTYPE; - connectionPublisherIdContext->elementClassiefier = UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID; + connectionPublisherIdContext->elementClassiefier = + UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID; UA_ValueCallback valueCallback; valueCallback.onRead = onRead; valueCallback.onWrite = NULL; - retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, connectionPublisherIdContext); + retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, + connectionPublisherIdContext); #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS retVal |= UA_Server_addReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true); + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), + true); retVal |= UA_Server_addReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true); + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), + true); retVal |= UA_Server_addReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), true); + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), + true); #endif return retVal; } @@ -31550,51 +33748,67 @@ addPubSubConnectionAction(UA_Server *server, size_t outputSize, UA_Variant *output){ UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_PubSubConnectionDataType pubSubConnectionDataType = *((UA_PubSubConnectionDataType *) input[0].data); - UA_NetworkAddressUrlDataType networkAddressUrlDataType; - memset(&networkAddressUrlDataType, 0, sizeof(networkAddressUrlDataType)); - UA_ExtensionObject eo = pubSubConnectionDataType.address; - if(eo.encoding == UA_EXTENSIONOBJECT_DECODED){ - if(eo.content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]){ - if(UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *) eo.content.decoded.data, - &networkAddressUrlDataType) != UA_STATUSCODE_GOOD){ - return UA_STATUSCODE_BADOUTOFMEMORY; - } - } - } - UA_PubSubConnectionConfig connectionConfig; - memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); - connectionConfig.transportProfileUri = pubSubConnectionDataType.transportProfileUri; - connectionConfig.name = pubSubConnectionDataType.name; - //TODO set real connection state - connectionConfig.enabled = pubSubConnectionDataType.enabled; - //connectionConfig.enabled = pubSubConnectionDataType.enabled; - UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrlDataType, - &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); - if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_UINT32]){ - connectionConfig.publisherId.numeric = * ((UA_UInt32 *) pubSubConnectionDataType.publisherId.data); - } else if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_STRING]){ - connectionConfig.publisherIdType = UA_PUBSUB_PUBLISHERID_STRING; - UA_String_copy((UA_String *) pubSubConnectionDataType.publisherId.data, &connectionConfig.publisherId.string); - } else { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Unsupported PublisherId Type used."); - //TODO what's the best default behaviour here? - connectionConfig.publisherId.numeric = 0; - } + //call API function and create the connection UA_NodeId connectionId; - - retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connectionId); - - if(retVal != UA_STATUSCODE_GOOD){ + retVal |= addPubSubConnectionConfig(server, &pubSubConnectionDataType, &connectionId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addPubSubConnection failed"); return retVal; } + for(size_t i = 0; i < pubSubConnectionDataType.writerGroupsSize; i++){ - //UA_PubSubConnection_addWriterGroup(server, UA_NODEID_NULL, NULL, NULL); + UA_NodeId writerGroupId; + UA_WriterGroupDataType *writerGroupDataType = &pubSubConnectionDataType.writerGroups[i]; + retVal |= addWriterGroupConfig(server, connectionId, writerGroupDataType, &writerGroupId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addWriterGroup failed"); + return retVal; + } + + for (size_t j = 0; j < pubSubConnectionDataType.writerGroups[i].dataSetWritersSize; j++){ + UA_DataSetWriterDataType *dataSetWriterDataType = &writerGroupDataType->dataSetWriters[j]; + retVal |= addDataSetWriterConfig(server, &writerGroupId, dataSetWriterDataType, NULL); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addDataSetWriter failed"); + return retVal; + } + } + + //TODO: Need to handle the UA_Server_setWriterGroupOperational based on the status variable in information model + if(pubSubConnectionDataType.enabled) { + UA_Server_freezeWriterGroupConfiguration(server, writerGroupId); + UA_Server_setWriterGroupOperational(server, writerGroupId); + } else + UA_Server_setWriterGroupDisabled(server, writerGroupId); } + for(size_t i = 0; i < pubSubConnectionDataType.readerGroupsSize; i++){ - //UA_Server_addReaderGroup(server, NULL, NULL, NULL); + UA_NodeId readerGroupId; + UA_ReaderGroupDataType *readerGroupDataType = &pubSubConnectionDataType.readerGroups[i]; + retVal |= addReaderGroupConfig(server, connectionId, readerGroupDataType, &readerGroupId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addReaderGroup failed"); + return retVal; + } + + for(size_t j = 0; j < pubSubConnectionDataType.readerGroups[i].dataSetReadersSize; j++){ + UA_NodeId dataSetReaderId; + UA_DataSetReaderDataType *dataSetReaderDataType = &readerGroupDataType->dataSetReaders[j]; + retVal |= addDataSetReaderConfig(server, readerGroupId, dataSetReaderDataType, &dataSetReaderId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addDataSetReader failed"); + return retVal; + } + } + //TODO: Need to handle the UA_Server_setReaderGroupOperational based on the status variable in information model + if(pubSubConnectionDataType.enabled) { + UA_Server_freezeReaderGroupConfiguration(server, readerGroupId); + UA_Server_setReaderGroupOperational(server, readerGroupId); + } + else + UA_Server_setReaderGroupDisabled(server, readerGroupId); } - UA_NetworkAddressUrlDataType_deleteMembers(&networkAddressUrlDataType); //set ouput value UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]); return UA_STATUSCODE_GOOD; @@ -31602,21 +33816,9 @@ addPubSubConnectionAction(UA_Server *server, #endif UA_StatusCode -removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS - retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), - false); - retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), - false); - retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), - false); -#endif - retVal |= UA_Server_deleteNode(server, connection->identifier, true); - return retVal; +removePubSubConnectionRepresentation(UA_Server *server, + UA_PubSubConnection *connection) { + return UA_Server_deleteNode(server, connection->identifier, true); } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -31641,8 +33843,64 @@ removeConnectionAction(UA_Server *server, /**********************************************/ UA_StatusCode addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader){ - //TODO implement reader part - return UA_STATUSCODE_BADNOTIMPLEMENTED; + if(dataSetReader->config.name.length > 512) + return UA_STATUSCODE_BADCONFIGURATIONERROR; + + char dsrName[513]; + memcpy(dsrName, dataSetReader->config.name.data, dataSetReader->config.name.length); + dsrName[dataSetReader->config.name.length] = '\0'; + + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_NodeId publisherIdNode, writerGroupIdNode, dataSetwriterIdNode; + + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.displayName = UA_LOCALIZEDTEXT("", dsrName); + retVal = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), /* create an id */ + dataSetReader->linkedReaderGroup, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASDATASETREADER), + UA_QUALIFIEDNAME(0, dsrName), + UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERTYPE), + object_attr, NULL, &dataSetReader->identifier); + + /* Add childNodes such as PublisherId, WriterGroupId and DataSetWriterId in + * DataSetReader object */ + publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + dataSetReader->identifier); + writerGroupIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + dataSetReader->identifier); + dataSetwriterIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + dataSetReader->identifier); + + if(UA_NodeId_isNull(&publisherIdNode) || + UA_NodeId_isNull(&writerGroupIdNode) || + UA_NodeId_isNull(&dataSetwriterIdNode)) { + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_NodePropertyContext *dataSetReaderPublisherIdContext = + (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext)); + dataSetReaderPublisherIdContext->parentNodeId = dataSetReader->identifier; + dataSetReaderPublisherIdContext->parentClassifier = UA_NS0ID_DATASETREADERTYPE; + dataSetReaderPublisherIdContext->elementClassiefier = UA_NS0ID_DATASETREADERTYPE_PUBLISHERID; + UA_ValueCallback valueCallback; + valueCallback.onRead = onRead; + valueCallback.onWrite = NULL; + retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, + dataSetReaderPublisherIdContext); + + /* Update childNode with values from Publisher */ + UA_Variant value; + UA_Variant_init(&value); + UA_Variant_setScalar(&value, &dataSetReader->config.writerGroupId, + &UA_TYPES[UA_TYPES_UINT16]); + UA_Server_writeValue(server, writerGroupIdNode, value); + UA_Variant_setScalar(&value, &dataSetReader->config.dataSetWriterId, + &UA_TYPES[UA_TYPES_UINT16]); + UA_Server_writeValue(server, dataSetwriterIdNode, value); + return retVal; } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -31653,16 +33911,31 @@ addDataSetReaderAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED; - //TODO implement reader part + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, *objectId); + if(rg->configurationFrozen) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "addDataSetReader cannot be done because ReaderGroup config frozen"); + return UA_STATUSCODE_BAD; + } + + UA_NodeId dataSetReaderId; + UA_DataSetReaderDataType *dataSetReaderDataType = (UA_DataSetReaderDataType *) input[0].data; + retVal |= addDataSetReaderConfig(server, *objectId, dataSetReaderDataType, &dataSetReaderId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addDataSetReader failed"); + return retVal; + } + + UA_Variant_setScalarCopy(output, &dataSetReaderId, &UA_TYPES[UA_TYPES_NODEID]); return retVal; } #endif UA_StatusCode -removeDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader* dataSetReader){ - //TODO implement reader part - return UA_STATUSCODE_BADNOTIMPLEMENTED; +removeDataSetReaderRepresentation(UA_Server *server, + UA_DataSetReader* dataSetReader) { + return UA_Server_deleteNode(server, dataSetReader->identifier, true); } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -31673,9 +33946,8 @@ removeDataSetReaderAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED; - //TODO implement reader part - return retVal; + UA_NodeId nodeToRemove = *((UA_NodeId *)input[0].data); + return UA_Server_removeDataSetReader(server, nodeToRemove); } #endif @@ -31695,10 +33967,12 @@ addDataSetFolderAction(UA_Server *server, UA_String newFolderName = *((UA_String *) input[0].data); UA_NodeId generatedId; UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default; - UA_LocalizedText name = {UA_STRING("en-US"), newFolderName}; + UA_LocalizedText name = {UA_STRING(""), newFolderName}; objectAttributes.displayName = name; - retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId, UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES), - UA_QUALIFIEDNAME(0, "DataSetFolder"), UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE), + retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId, + UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES), + UA_QUALIFIEDNAME(0, "DataSetFolder"), + UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE), objectAttributes, NULL, &generatedId); UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]); #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -31726,55 +34000,44 @@ removeDataSetFolderAction(UA_Server *server, const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, - size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; + size_t outputSize, UA_Variant *output) { UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data); -#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS - retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), - false); - retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), - false); - retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), - false); - retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, - UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), - false); -#endif - retVal |= UA_Server_deleteNode(server, nodeToRemove, false); - return retVal; + return UA_Server_deleteNode(server, nodeToRemove, true); } #endif UA_StatusCode -addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet) { +addPublishedDataItemsRepresentation(UA_Server *server, + UA_PublishedDataSet *publishedDataSet) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; if(publishedDataSet->config.name.length > 512) return UA_STATUSCODE_BADOUTOFMEMORY; - UA_STACKARRAY(char, pdsName, sizeof(char) * publishedDataSet->config.name.length +1); + char pdsName[513]; memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length); pdsName[publishedDataSet->config.name.length] = '\0'; - //This code block must use a lock - UA_NODESTORE_REMOVE(server, &publishedDataSet->identifier); - retVal |= addPubSubObjectNode(server, pdsName, publishedDataSet->identifier.identifier.numeric, - UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS, - UA_NS0ID_HASPROPERTY, UA_NS0ID_PUBLISHEDDATAITEMSTYPE); - //End lock zone + + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.displayName = UA_LOCALIZEDTEXT("", pdsName); + retVal = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), /* Create a new id */ + UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(0, pdsName), + UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE), + object_attr, NULL, &publishedDataSet->identifier); + UA_CHECK_STATUS(retVal, return retVal); UA_ValueCallback valueCallback; valueCallback.onRead = onRead; valueCallback.onWrite = NULL; - + //ToDo: Need to move the browse name from namespaceindex 0 to 1 UA_NodeId configurationVersionNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric)); - if(UA_NodeId_equal(&configurationVersionNode, &UA_NODEID_NULL)) + publishedDataSet->identifier); + if(UA_NodeId_isNull(&configurationVersionNode)) return UA_STATUSCODE_BADNOTFOUND; - UA_NodePropertyContext * configurationVersionContext = (UA_NodePropertyContext *) + UA_NodePropertyContext *configurationVersionContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext)); configurationVersionContext->parentNodeId = publishedDataSet->identifier; configurationVersionContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE; @@ -31786,8 +34049,8 @@ addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publ UA_NodeId publishedDataNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric)); - if(UA_NodeId_equal(&publishedDataNode, &UA_NODEID_NULL)) + publishedDataSet->identifier); + if(UA_NodeId_isNull(&publishedDataNode)) return UA_STATUSCODE_BADNOTFOUND; UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *) @@ -31801,8 +34064,8 @@ addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publ UA_NodeId dataSetMetaDataNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric)); - if(UA_NodeId_equal(&dataSetMetaDataNode, &UA_NODEID_NULL)) + publishedDataSet->identifier); + if(UA_NodeId_isNull(&dataSetMetaDataNode)) return UA_STATUSCODE_BADNOTFOUND; UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *) @@ -31810,7 +34073,8 @@ addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publ metaDataContext->parentNodeId = publishedDataSet->identifier; metaDataContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE; metaDataContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA; - retVal |= addVariableValueSource(server, valueCallback, dataSetMetaDataNode, metaDataContext); + retVal |= addVariableValueSource(server, valueCallback, + dataSetMetaDataNode, metaDataContext); #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS retVal |= UA_Server_addReference(server, publishedDataSet->identifier, @@ -31837,7 +34101,7 @@ addPublishedDataItemsAction(UA_Server *server, size_t fieldFlagsSize = input[2].arrayLength; UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data; size_t variablesToAddSize = input[3].arrayLength; - UA_PublishedVariableDataType *variablesToAddField = (UA_PublishedVariableDataType *) input[3].data; + UA_ExtensionObject *eoAddVar = (UA_ExtensionObject *)input[3].data; if(!(fieldNameAliasesSize == fieldFlagsSize || fieldFlagsSize == variablesToAddSize)) return UA_STATUSCODE_BADINVALIDARGUMENT; @@ -31848,20 +34112,43 @@ addPublishedDataItemsAction(UA_Server *server, publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS; UA_NodeId dataSetItemsNodeId; - retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &dataSetItemsNodeId).addResult; + retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, + &dataSetItemsNodeId).addResult; + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "addPublishedDataset failed"); + return retVal; + } UA_DataSetFieldConfig dataSetFieldConfig; for(size_t j = 0; j < variablesToAddSize; ++j) { - memset(&dataSetFieldConfig, 0, sizeof(dataSetFieldConfig)); + memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig)); dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE; dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j]; - if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD){ - dataSetFieldConfig.field.variable.promotedField = UA_TRUE; + if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD) + dataSetFieldConfig.field.variable.promotedField = true; + + UA_PublishedVariableDataType variablesToAddField; + UA_PublishedVariableDataType_init(&variablesToAddField); + if(eoAddVar[j].encoding == UA_EXTENSIONOBJECT_DECODED){ + if(eoAddVar[j].content.decoded.type == &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]){ + if(UA_PublishedVariableDataType_copy((UA_PublishedVariableDataType *) eoAddVar[j].content.decoded.data, + &variablesToAddField) != UA_STATUSCODE_GOOD){ + return UA_STATUSCODE_BADOUTOFMEMORY; + } + } } - dataSetFieldConfig.field.variable.publishParameters = variablesToAddField[j]; - UA_Server_addDataSetField(server, dataSetItemsNodeId, &dataSetFieldConfig, NULL); + dataSetFieldConfig.field.variable.publishParameters = variablesToAddField; + retVal |= UA_Server_addDataSetField(server, dataSetItemsNodeId, &dataSetFieldConfig, NULL).result; + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addDataSetField failed"); + return retVal; + } + + UA_PublishedVariableDataType_clear(&variablesToAddField); } - UA_PublishedVariableDataType_clear(variablesToAddField); + + UA_Variant_setScalarCopy(output, &dataSetItemsNodeId, &UA_TYPES[UA_TYPES_NODEID]); return retVal; } #endif @@ -31874,9 +34161,7 @@ addVariablesAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - - return retVal; + return UA_STATUSCODE_GOOD; } static UA_StatusCode @@ -31886,19 +34171,15 @@ removeVariablesAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - - return retVal; + return UA_STATUSCODE_GOOD; } #endif UA_StatusCode -removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - retVal |= UA_Server_deleteNode(server, publishedDataSet->identifier, false); - - return retVal; +removePublishedDataSetRepresentation(UA_Server *server, + UA_PublishedDataSet *publishedDataSet) { + return UA_Server_deleteNode(server, publishedDataSet->identifier, true); } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -31909,10 +34190,8 @@ removePublishedDataSetAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data); - retVal |= UA_Server_removePublishedDataSet(server, nodeToRemove); - return retVal; + return UA_Server_removePublishedDataSet(server, nodeToRemove); } #endif @@ -31969,25 +34248,29 @@ addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){ UA_StatusCode retVal = UA_STATUSCODE_GOOD; if(writerGroup->config.name.length > 512) return UA_STATUSCODE_BADOUTOFMEMORY; - UA_STACKARRAY(char, wgName, sizeof(char) * writerGroup->config.name.length + 1); + char wgName[513]; memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length); wgName[writerGroup->config.name.length] = '\0'; - //This code block must use a lock - UA_NODESTORE_REMOVE(server, &writerGroup->identifier); - retVal |= addPubSubObjectNode(server, wgName, writerGroup->identifier.identifier.numeric, - writerGroup->linkedConnection->identifier.identifier.numeric, - UA_NS0ID_HASCOMPONENT, UA_NS0ID_WRITERGROUPTYPE); - //End lock zone + + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.displayName = UA_LOCALIZEDTEXT("", wgName); + retVal = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), /* create a new id */ + writerGroup->linkedConnection->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(0, wgName), + UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), + object_attr, NULL, &writerGroup->identifier); + UA_NodeId keepAliveNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric)); + writerGroup->identifier); UA_NodeId publishingIntervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric)); - if(UA_NodeId_equal(&keepAliveNode, &UA_NODEID_NULL) || - UA_NodeId_equal(&publishingIntervalNode, &UA_NODEID_NULL)) + writerGroup->identifier); + if(UA_NodeId_isNull(&keepAliveNode) || + UA_NodeId_isNull(&publishingIntervalNode)) return UA_STATUSCODE_BADNOTFOUND; UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *) @@ -32006,11 +34289,12 @@ addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){ UA_NodeId priorityNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric)); + writerGroup->identifier); UA_NodeId writerGroupIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), - UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric)); + writerGroup->identifier); + UA_Variant value; UA_Variant_init(&value); UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]); @@ -32022,34 +34306,46 @@ addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){ UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]); UA_Server_writeValue(server, writerGroupIdNode, value); - retVal |= addPubSubObjectNode(server, "MessageSettings", 0, - writerGroup->identifier.identifier.numeric, - UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPWRITERGROUPMESSAGETYPE); + object_attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings"); + retVal |= UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), + writerGroup->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(0, "MessageSettings"), + UA_NODEID_NUMERIC(0, UA_NS0ID_UADPWRITERGROUPMESSAGETYPE), + object_attr, NULL, NULL); /* Find the variable with the content mask */ UA_NodeId messageSettingsId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "MessageSettings"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), - UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric)); + writerGroup->identifier); UA_NodeId contentMaskId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkMessageContentMask"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), messageSettingsId); - if(UA_NodeId_equal(&messageSettingsId, &UA_NODEID_NULL) || - UA_NodeId_equal(&contentMaskId, &UA_NODEID_NULL)) { - return UA_STATUSCODE_BADNOTFOUND; - } + if(!UA_NodeId_isNull(&contentMaskId)) { + /* Set the callback */ + UA_DataSource ds; + ds.read = readContentMask; + ds.write = writeContentMask; + UA_Server_setVariableNode_dataSource(server, contentMaskId, ds); + UA_Server_setNodeContext(server, contentMaskId, writerGroup); + + /* Make writable */ + UA_Server_writeAccessLevel(server, contentMaskId, + UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ); - /* Set the callback */ - UA_DataSource ds; - ds.read = readContentMask; - ds.write = writeContentMask; - UA_Server_setVariableNode_dataSource(server, contentMaskId, ds); - UA_Server_setNodeContext(server, contentMaskId, writerGroup); + } - /* Make writable */ - UA_Server_writeAccessLevel(server, contentMaskId, - UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ); + /* Add reference to methods */ +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS + retVal |= UA_Server_addReference(server, writerGroup->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), true); + retVal |= UA_Server_addReference(server, writerGroup->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), true); +#endif return retVal; } @@ -32064,55 +34360,81 @@ addWriterGroupAction(UA_Server *server, size_t outputSize, UA_Variant *output){ UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_WriterGroupDataType *writerGroupDataType = ((UA_WriterGroupDataType *) input[0].data); - UA_NodeId generatedId; - UA_WriterGroupConfig writerGroupConfig; - memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig)); - writerGroupConfig.name = writerGroupDataType->name; - writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval; - writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId; - writerGroupConfig.enabled = writerGroupDataType->enabled; - writerGroupConfig.priority = writerGroupDataType->priority; - //TODO remove hard coded UADP - writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP; - //ToDo transfer all arguments to internal WGConfiguration - retVal |= UA_Server_addWriterGroup(server, *objectId, &writerGroupConfig, &generatedId); - UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]); + UA_NodeId writerGroupId; + retVal |= addWriterGroupConfig(server, *objectId, writerGroupDataType, &writerGroupId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addWriterGroup failed"); + return retVal; + } + //TODO: Need to handle the UA_Server_setWriterGroupOperational based on the status variable in information model + + UA_Variant_setScalarCopy(output, &writerGroupId, &UA_TYPES[UA_TYPES_NODEID]); return retVal; } #endif UA_StatusCode removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) { - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - retVal |= UA_Server_deleteNode(server, writerGroup->identifier, false); - return retVal; + return UA_Server_deleteNode(server, writerGroup->identifier, true); +} + +UA_StatusCode +removeReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup) { + return UA_Server_deleteNode(server, readerGroup->identifier, true); } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS static UA_StatusCode removeGroupAction(UA_Server *server, - const UA_NodeId *sessionId, void *sessionHandle, - const UA_NodeId *methodId, void *methodContext, - const UA_NodeId *objectId, void *objectContext, - size_t inputSize, const UA_Variant *input, - size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data); - if(UA_WriterGroup_findWGbyId(server, nodeToRemove) != NULL) - retVal |= UA_Server_removeWriterGroup(server, nodeToRemove); - //else - //retVal |= UA_Server_removeReaderGroup(server, nodeToRemve); - return retVal; + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output){ + UA_NodeId nodeToRemove = *((UA_NodeId *)input->data); + if(UA_WriterGroup_findWGbyId(server, nodeToRemove)) { + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, nodeToRemove); + if(wg->configurationFrozen) + UA_Server_unfreezeWriterGroupConfiguration(server, nodeToRemove); + return UA_Server_removeWriterGroup(server, nodeToRemove); + } else { + UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, nodeToRemove); + if(rg->configurationFrozen) + UA_Server_unfreezeReaderGroupConfiguration(server, nodeToRemove); + return UA_Server_removeReaderGroup(server, nodeToRemove); + } } #endif /**********************************************/ /* ReaderGroup */ /**********************************************/ + UA_StatusCode -addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup){ - //TODO implement reader part - return UA_STATUSCODE_BADNOTIMPLEMENTED; +addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup) { + if(readerGroup->config.name.length > 512) + return UA_STATUSCODE_BADCONFIGURATIONERROR; + char rgName[513]; + memcpy(rgName, readerGroup->config.name.data, readerGroup->config.name.length); + rgName[readerGroup->config.name.length] = '\0'; + + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.displayName = UA_LOCALIZEDTEXT("", rgName); + UA_StatusCode retVal = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), /* create an id */ + readerGroup->linkedConnection, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(0, rgName), + UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE), + object_attr, NULL, &readerGroup->identifier); +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS + retVal |= UA_Server_addReference(server, readerGroup->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), true); + retVal |= UA_Server_addReference(server, readerGroup->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), true); +#endif + return retVal; } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -32124,7 +34446,16 @@ addReaderGroupAction(UA_Server *server, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ UA_StatusCode retVal = UA_STATUSCODE_GOOD; - //TODO implement reader part + UA_ReaderGroupDataType *readerGroupDataType = ((UA_ReaderGroupDataType *) input->data); + UA_NodeId readerGroupId; + retVal |= addReaderGroupConfig(server, *objectId, readerGroupDataType, &readerGroupId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "addReaderGroup failed"); + return retVal; + } + //TODO: Need to handle the UA_Server_setReaderGroupOperational based on the status variable in information model + + UA_Variant_setScalarCopy(output, &readerGroupId, &UA_TYPES[UA_TYPES_NODEID]); return retVal; } #endif @@ -32132,28 +34463,73 @@ addReaderGroupAction(UA_Server *server, /**********************************************/ /* DataSetWriter */ /**********************************************/ + UA_StatusCode addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter){ UA_StatusCode retVal = UA_STATUSCODE_GOOD; if(dataSetWriter->config.name.length > 512) return UA_STATUSCODE_BADOUTOFMEMORY; - UA_STACKARRAY(char, dswName, sizeof(char) * dataSetWriter->config.name.length + 1); + char dswName[513]; memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length); dswName[dataSetWriter->config.name.length] = '\0'; - //This code block must use a lock - UA_NODESTORE_REMOVE(server, &dataSetWriter->identifier); - retVal |= addPubSubObjectNode(server, dswName, dataSetWriter->identifier.identifier.numeric, - dataSetWriter->linkedWriterGroup.identifier.numeric, - UA_NS0ID_HASDATASETWRITER, UA_NS0ID_DATASETWRITERTYPE); - //End lock zone + + UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; + object_attr.displayName = UA_LOCALIZEDTEXT("", dswName); + retVal = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), /* create an id */ + dataSetWriter->linkedWriterGroup, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASDATASETWRITER), + UA_QUALIFIEDNAME(0, dswName), + UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERTYPE), + object_attr, NULL, &dataSetWriter->identifier); + retVal |= UA_Server_addReference(server, dataSetWriter->connectedDataSet, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETTOWRITER), - UA_EXPANDEDNODEID_NUMERIC(0, dataSetWriter->identifier.identifier.numeric), true); + UA_EXPANDEDNODEID_NODEID(dataSetWriter->identifier), + true); + UA_NodeId dataSetWriterIdNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + dataSetWriter->identifier); + UA_NodeId keyFrameNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeyFrameCount"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + dataSetWriter->identifier); + UA_NodeId dataSetFieldContentMaskNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetFieldContentMask"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), + dataSetWriter->identifier); - retVal |= addPubSubObjectNode(server, "MessageSettings", 0, - dataSetWriter->identifier.identifier.numeric, - UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPDATASETWRITERMESSAGETYPE); + UA_NodePropertyContext *dataSetWriterIdContext = (UA_NodePropertyContext *) + UA_malloc(sizeof(UA_NodePropertyContext)); + dataSetWriterIdContext->parentNodeId = dataSetWriter->identifier; + dataSetWriterIdContext->parentClassifier = UA_NS0ID_DATASETWRITERTYPE; + dataSetWriterIdContext->elementClassiefier = UA_NS0ID_DATASETWRITERTYPE_DATASETWRITERID; + UA_ValueCallback valueCallback; + valueCallback.onRead = onRead; + valueCallback.onWrite = NULL; + retVal |= addVariableValueSource(server, valueCallback, + dataSetWriterIdNode, dataSetWriterIdContext); + + UA_Variant value; + UA_Variant_init(&value); + UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetWriterId, + &UA_TYPES[UA_TYPES_UINT16]); + UA_Server_writeValue(server, dataSetWriterIdNode, value); + UA_Variant_setScalar(&value, &dataSetWriter->config.keyFrameCount, + &UA_TYPES[UA_TYPES_UINT32]); + UA_Server_writeValue(server, keyFrameNode, value); + UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetFieldContentMask, + &UA_TYPES[UA_TYPES_DATASETFIELDCONTENTMASK]); + UA_Server_writeValue(server, dataSetFieldContentMaskNode, value); + + object_attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings"); + retVal |= UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), + dataSetWriter->identifier, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_QUALIFIEDNAME(0, "MessageSettings"), + UA_NODEID_NUMERIC(0, UA_NS0ID_UADPDATASETWRITERMESSAGETYPE), + object_attr, NULL, NULL); return retVal; } @@ -32165,39 +34541,38 @@ addDataSetWriterAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_DataSetWriterDataType *dataSetWriterDataType = (UA_DataSetWriterDataType *) input[0].data; - - UA_NodeId targetPDS = UA_NODEID_NULL; - UA_PublishedDataSet *tmpPDS; - TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry){ - if(UA_String_equal(&dataSetWriterDataType->dataSetName, &tmpPDS->config.name)){ - targetPDS = tmpPDS->identifier; - } + UA_StatusCode retVal = UA_STATUSCODE_GOOD; + UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, *objectId); + if(!wg) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Not a WriterGroup"); + return UA_STATUSCODE_BAD; + } + if(wg->configurationFrozen) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "addDataSetWriter cannot be done because writergroup config frozen"); + return UA_STATUSCODE_BAD; } - if(UA_NodeId_isNull(&targetPDS)) - return UA_STATUSCODE_BADPARENTNODEIDINVALID; - - UA_NodeId generatedId; - UA_DataSetWriterConfig dataSetWriterConfig; - memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig)); - dataSetWriterConfig.name = dataSetWriterDataType->name; - dataSetWriterConfig.dataSetName = dataSetWriterDataType->dataSetName; - dataSetWriterConfig.keyFrameCount = dataSetWriterDataType->keyFrameCount; - dataSetWriterConfig.dataSetWriterId = dataSetWriterDataType->dataSetWriterId; + UA_NodeId dataSetWriterId; + UA_DataSetWriterDataType *dataSetWriterData = (UA_DataSetWriterDataType *)input->data; + retVal |= addDataSetWriterConfig(server, objectId, dataSetWriterData, &dataSetWriterId); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "addDataSetWriter failed"); + return retVal; + } - UA_Server_addDataSetWriter(server, *objectId, targetPDS, &dataSetWriterConfig, &generatedId); - UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]); + UA_Variant_setScalarCopy(output, &dataSetWriterId, &UA_TYPES[UA_TYPES_NODEID]); return UA_STATUSCODE_GOOD; } #endif UA_StatusCode -removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) { - UA_StatusCode retVal = UA_STATUSCODE_GOOD; - retVal |= UA_Server_deleteNode(server, dataSetWriter->identifier, false); - return retVal; +removeDataSetWriterRepresentation(UA_Server *server, + UA_DataSetWriter *dataSetWriter) { + return UA_Server_deleteNode(server, dataSetWriter->identifier, true); } #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS @@ -32208,10 +34583,8 @@ removeDataSetWriterAction(UA_Server *server, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output){ - UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data); - retVal |= UA_Server_removeDataSetWriter(server, nodeToRemove); - return retVal; + return UA_Server_removeDataSetWriter(server, nodeToRemove); } #endif @@ -32224,16 +34597,15 @@ connectionTypeDestructor(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *typeId, void *typeContext, const UA_NodeId *nodeId, void **nodeContext) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Connection destructor called!"); - UA_NodeId publisherIdNode; - publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); - UA_NodePropertyContext *internalConnectionContext; - UA_Server_getNodeContext(server, publisherIdNode, (void **) &internalConnectionContext); - if(!UA_NodeId_equal(&UA_NODEID_NULL , &publisherIdNode)){ - UA_free(internalConnectionContext); - } - + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, + "Connection destructor called!"); + UA_NodeId publisherIdNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); + UA_NodePropertyContext *ctx; + UA_Server_getNodeContext(server, publisherIdNode, (void **)&ctx); + if(!UA_NodeId_isNull(&publisherIdNode)) + UA_free(ctx); } static void @@ -32241,15 +34613,15 @@ writerGroupTypeDestructor(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *typeId, void *typeContext, const UA_NodeId *nodeId, void **nodeContext) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "WriterGroup destructor called!"); - UA_NodeId intervalNode; - intervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"), - UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); - UA_NodePropertyContext *internalConnectionContext; - UA_Server_getNodeContext(server, intervalNode, (void **) &internalConnectionContext); - if(!UA_NodeId_equal(&UA_NODEID_NULL , &intervalNode)){ - UA_free(internalConnectionContext); - } + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, + "WriterGroup destructor called!"); + UA_NodeId intervalNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); + UA_NodePropertyContext *ctx; + UA_Server_getNodeContext(server, intervalNode, (void **)&ctx); + if(!UA_NodeId_isNull(&intervalNode)) + UA_free(ctx); } static void @@ -32257,7 +34629,8 @@ readerGroupTypeDestructor(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *typeId, void *typeContext, const UA_NodeId *nodeId, void **nodeContext) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "ReaderGroup destructor called!"); + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, + "ReaderGroup destructor called!"); } static void @@ -32265,7 +34638,15 @@ dataSetWriterTypeDestructor(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *typeId, void *typeContext, const UA_NodeId *nodeId, void **nodeContext) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetWriter destructor called!"); + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, + "DataSetWriter destructor called!"); + UA_NodeId dataSetWriterIdNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); + UA_NodePropertyContext *ctx; + UA_Server_getNodeContext(server, dataSetWriterIdNode, (void **)&ctx); + if(!UA_NodeId_isNull(&dataSetWriterIdNode)) + UA_free(ctx); } static void @@ -32273,7 +34654,17 @@ dataSetReaderTypeDestructor(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *typeId, void *typeContext, const UA_NodeId *nodeId, void **nodeContext) { - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetReader destructor called!"); + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, + "DataSetReader destructor called!"); + + /* Deallocate the memory allocated for publisherId */ + UA_NodeId publisherIdNode = + findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); + UA_NodePropertyContext *ctx; + UA_Server_getNodeContext(server, publisherIdNode, (void **)&ctx); + if(!UA_NodeId_isNull(&publisherIdNode)) + UA_free(ctx); } static void @@ -32287,23 +34678,104 @@ publishedDataItemsTypeDestructor(UA_Server *server, UA_NodeId node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); UA_Server_getNodeContext(server, node, (void**)&childContext); - if(!UA_NodeId_equal(&UA_NODEID_NULL , &node)) + if(!UA_NodeId_isNull(&node)) UA_free(childContext); node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); UA_Server_getNodeContext(server, node, (void**)&childContext); - if(!UA_NodeId_equal(&UA_NODEID_NULL , &node)) + if(!UA_NodeId_isNull(&node)) UA_free(childContext); node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId); UA_Server_getNodeContext(server, node, (void**)&childContext); - if(!UA_NodeId_equal(&node, &UA_NODEID_NULL)) + if(!UA_NodeId_isNull(&node)) UA_free(childContext); } +/*************************************/ +/* PubSub configurator */ +/*************************************/ + +#if defined(UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS) && defined(UA_ENABLE_PUBSUB_FILE_CONFIG) + +/* Callback function that will be executed when the method "PubSub configurator + * (replace config)" is called. */ +static UA_StatusCode +UA_loadPubSubConfigMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + if(inputSize == 1) { + UA_ByteString *inputStr = (UA_ByteString*)input->data; + return UA_PubSubManager_loadPubSubConfigFromByteString(server, *inputStr); + } else if(inputSize > 1) { + return UA_STATUSCODE_BADTOOMANYARGUMENTS; + } else { + return UA_STATUSCODE_BADARGUMENTSMISSING; + } +} + +/* Adds method node to server. This method is used to load binary files for + * PubSub configuration and delete / replace old PubSub configurations. */ +static UA_StatusCode +UA_addLoadPubSubConfigMethod(UA_Server *server) { + UA_Argument inputArgument; + UA_Argument_init(&inputArgument); + inputArgument.description = UA_LOCALIZEDTEXT("", "PubSub config binfile"); + inputArgument.name = UA_STRING("BinFile"); + inputArgument.dataType = UA_TYPES[UA_TYPES_BYTESTRING].typeId; + inputArgument.valueRank = UA_VALUERANK_SCALAR; + + UA_MethodAttributes configAttr = UA_MethodAttributes_default; + configAttr.description = UA_LOCALIZEDTEXT("","Load binary configuration file"); + configAttr.displayName = UA_LOCALIZEDTEXT("","LoadPubSubConfigurationFile"); + configAttr.executable = true; + configAttr.userExecutable = true; + return UA_Server_addMethodNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT), + UA_QUALIFIEDNAME(1, "PubSub configuration"), + configAttr, &UA_loadPubSubConfigMethodCallback, + 1, &inputArgument, 0, NULL, NULL, NULL); +} + +/* Callback function that will be executed when the method "PubSub configurator + * (delete config)" is called. */ +static UA_StatusCode +UA_deletePubSubConfigMethodCallback(UA_Server *server, + const UA_NodeId *sessionId, void *sessionHandle, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext, + size_t inputSize, const UA_Variant *input, + size_t outputSize, UA_Variant *output) { + UA_PubSubManager_delete(server, &(server->pubSubManager)); + return UA_STATUSCODE_GOOD; +} + +/* Adds method node to server. This method is used to delete the current PubSub + * configuration. */ +static UA_StatusCode +UA_addDeletePubSubConfigMethod(UA_Server *server) { + UA_MethodAttributes configAttr = UA_MethodAttributes_default; + configAttr.description = UA_LOCALIZEDTEXT("","Delete current PubSub configuration"); + configAttr.displayName = UA_LOCALIZEDTEXT("","DeletePubSubConfiguration"); + configAttr.executable = true; + configAttr.userExecutable = true; + return UA_Server_addMethodNode(server, UA_NODEID_NULL, + UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT), + UA_QUALIFIEDNAME(1, "Delete PubSub config"), + configAttr, &UA_deletePubSubConfigMethodCallback, + 0, NULL, 0, NULL, NULL, NULL); +} + +#endif /* defined(UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS) && defined(UA_ENABLE_PUBSUB_FILE_CONFIG) */ + UA_StatusCode UA_Server_initPubSubNS0(UA_Server *server) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -32311,14 +34783,10 @@ UA_Server_initPubSubNS0(UA_Server *server) { profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); retVal |= writePubSubNs0VariableArray(server, UA_NS0ID_PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES, - profileArray, - 1, &UA_TYPES[UA_TYPES_STRING]); + profileArray, 1, &UA_TYPES[UA_TYPES_STRING]); #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction); + /* Add missing references */ retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true); @@ -32331,55 +34799,69 @@ UA_Server_initPubSubNS0(UA_Server *server) { retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction); - retVal |= UA_Server_setMethodNode_callback(server, - UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction); - retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction); + + /* Set method callbacks */ + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction); + retVal |= UA_Server_setMethodNodeCallback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction); + +#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG + retVal |= UA_addLoadPubSubConfigMethod(server); + retVal |= UA_addDeletePubSubConfigMethod(server); +#endif #else - retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, + /* Remove methods */ + retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), false); - retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, + retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), false); #endif - UA_NodeTypeLifecycle liveCycle; - liveCycle.constructor = NULL; - liveCycle.destructor = connectionTypeDestructor; - UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), liveCycle); - liveCycle.destructor = writerGroupTypeDestructor; - UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), liveCycle); - liveCycle.destructor = readerGroupTypeDestructor; - UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE), liveCycle); - liveCycle.destructor = dataSetWriterTypeDestructor; - UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERDATATYPE), liveCycle); - liveCycle.destructor = publishedDataItemsTypeDestructor; - UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE), liveCycle); - liveCycle.destructor = dataSetReaderTypeDestructor; - UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERDATATYPE), liveCycle); + + /* Set the object-type destructors */ + UA_NodeTypeLifecycle lifeCycle; + lifeCycle.constructor = NULL; + + lifeCycle.destructor = connectionTypeDestructor; + retVal |= UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), lifeCycle); + + lifeCycle.destructor = writerGroupTypeDestructor; + retVal |= UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), lifeCycle); + + lifeCycle.destructor = readerGroupTypeDestructor; + retVal |= UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE), lifeCycle); + + lifeCycle.destructor = dataSetWriterTypeDestructor; + retVal |= UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERTYPE), lifeCycle); + + lifeCycle.destructor = publishedDataItemsTypeDestructor; + retVal |= UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE), lifeCycle); + + lifeCycle.destructor = dataSetReaderTypeDestructor; + retVal |= UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERTYPE), lifeCycle); return retVal; } #endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_view.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_view.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -32400,31 +34882,143 @@ UA_Server_initPubSubNS0(UA_Server *server) { */ -/********************/ -/* Browse Recursive */ -/********************/ +#define UA_MAX_TREE_RECURSE 50 /* How deep up/down the tree do we recurse at most? */ -/* A RefTree holds a single array for both the NodeIds encountered during - * recursive browsing and the entries for a tree-structure to check for - * duplicates. Once the (recursive) browse has finished, the tree-structure part - * can be simply cut away. A single realloc operation (with some pointer - * repairing) can be used to increase the capacity of the RefTree. - * - * If an ExpandedNodeId is encountered, it has to be processed right away. - * Remote ExpandedNodeId are not put into the tree, since it is not possible to - * recurse into them anyway. - * - * The layout of the results array is as follows: - * - * | Targets [ExpandedNodeId] | Tree [RefEntry] | */ +UA_StatusCode +referenceTypeIndices(UA_Server *server, const UA_NodeId *refType, + UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes) { + if(UA_NodeId_isNull(refType)) { + UA_ReferenceTypeSet_any(indices); + return UA_STATUSCODE_GOOD; + } -#define UA_BROWSE_INITIAL_SIZE 16 + UA_ReferenceTypeSet_init(indices); + const UA_Node *refNode = UA_NODESTORE_GET(server, refType); + if(!refNode) + return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; -typedef struct RefEntry { - ZIP_ENTRY(RefEntry) zipfields; - const UA_ExpandedNodeId *target; - UA_UInt32 targetHash; /* Hash of the target nodeid */ -} RefEntry; + if(refNode->head.nodeClass != UA_NODECLASS_REFERENCETYPE) { + UA_NODESTORE_RELEASE(server, refNode); + return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + } + + if(!includeSubtypes) + *indices = UA_REFTYPESET(refNode->referenceTypeNode.referenceTypeIndex); + else + *indices = refNode->referenceTypeNode.subTypes; + + UA_NODESTORE_RELEASE(server, refNode); + return UA_STATUSCODE_GOOD; +} + +static UA_Boolean +matchClassMask(const UA_Node *node, UA_UInt32 nodeClassMask) { + if(nodeClassMask != UA_NODECLASS_UNSPECIFIED && + (node->head.nodeClass & nodeClassMask) == 0) + return false; + return true; +} + +/****************/ +/* IsNodeInTree */ +/****************/ + +/* Internal method to check if a node is already upwards from a leaf node */ + +/* Keeps track of visited nodes to detect circular references */ +struct ref_history { + struct ref_history *parent; /* the previous element */ + const UA_NodePointer id; /* the id of the node at this depth */ + UA_UInt16 depth; +}; + +static UA_Boolean +isNodeInTreeNoCircular(UA_Server *server, + UA_NodePointer leafNode, + UA_NodePointer nodeToFind, + struct ref_history *visitedRefs, + const UA_ReferenceTypeSet *relevantRefs) { + if(UA_NodePointer_equal(nodeToFind, leafNode)) + return true; + + if(visitedRefs->depth >= UA_MAX_TREE_RECURSE) + return false; + + const UA_Node *node = UA_NODESTORE_GETFROMREF(server, leafNode); + if(!node) + return false; + + for(size_t i = 0; i < node->head.referencesSize; ++i) { + UA_NodeReferenceKind *rk = &node->head.references[i]; + /* Search upwards in the tree */ + if(!rk->isInverse) + continue; + + /* Consider only the indicated reference types */ + if(!UA_ReferenceTypeSet_contains(relevantRefs, rk->referenceTypeIndex)) + continue; + + /* Match the targets or recurse */ + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + /* Don't follow remote targets */ + if(!UA_NodePointer_isLocal(t->targetId)) + continue; + + /* Check if we already have seen the referenced node and skip to + * avoid endless recursion. Do this only at every 5th depth to save + * effort. Circular dependencies are rare and forbidden for most + * reference types. */ + if(visitedRefs->depth % 5 == 4) { + struct ref_history *last = visitedRefs; + UA_Boolean skip = false; + while(last) { + if(UA_NodePointer_equal(last->id, t->targetId)) { + skip = true; + break; + } + last = last->parent; + } + if(skip) + continue; + } + + /* Stack-allocate the visitedRefs structure for the next depth */ + struct ref_history nextVisitedRefs = {visitedRefs, t->targetId, + (UA_UInt16)(visitedRefs->depth+1)}; + + /* Recurse */ + UA_Boolean foundRecursive = + isNodeInTreeNoCircular(server, t->targetId, nodeToFind, + &nextVisitedRefs, relevantRefs); + if(foundRecursive) { + UA_NODESTORE_RELEASE(server, node); + return true; + } + } + } + + UA_NODESTORE_RELEASE(server, node); + return false; +} + +UA_Boolean +isNodeInTree(UA_Server *server, const UA_NodeId *leafNode, + const UA_NodeId *nodeToFind, + const UA_ReferenceTypeSet *relevantRefs) { + UA_NodePointer leafP = UA_NodePointer_fromNodeId(leafNode); + UA_NodePointer targetP = UA_NodePointer_fromNodeId(nodeToFind); + struct ref_history visitedRefs = {NULL, leafP, 0}; + return isNodeInTreeNoCircular(server, leafP, targetP, + &visitedRefs, relevantRefs); +} + +UA_Boolean +isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode, + const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex) { + UA_ReferenceTypeSet reftypes = UA_REFTYPESET(relevantRefTypeIndex); + return isNodeInTree(server, leafNode, nodeToFind, &reftypes); +} static enum ZIP_CMP cmpTarget(const void *a, const void *b) { @@ -32437,32 +35031,22 @@ cmpTarget(const void *a, const void *b) { return (enum ZIP_CMP)UA_ExpandedNodeId_order(aa->target, bb->target); } -ZIP_HEAD(RefHead, RefEntry); -typedef struct RefHead RefHead; -ZIP_PROTTYPE(RefHead, RefEntry, RefEntry) -ZIP_IMPL(RefHead, RefEntry, zipfields, RefEntry, zipfields, cmpTarget) +ZIP_FUNCTIONS(RefHead, RefEntry, zipfields, RefEntry, zipfields, cmpTarget) -typedef struct { - UA_ExpandedNodeId *targets; - RefHead head; - size_t capacity; /* available space */ - size_t size; /* used space */ -} RefTree; - -static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT +UA_StatusCode RefTree_init(RefTree *rt) { rt->size = 0; rt->capacity = 0; ZIP_INIT(&rt->head); - size_t space = (sizeof(UA_ExpandedNodeId) + sizeof(RefEntry)) * UA_BROWSE_INITIAL_SIZE; + size_t space = (sizeof(UA_ExpandedNodeId) + sizeof(RefEntry)) * UA_REFTREE_INITIAL_SIZE; rt->targets = (UA_ExpandedNodeId*)UA_malloc(space); if(!rt->targets) return UA_STATUSCODE_BADOUTOFMEMORY; - rt->capacity = UA_BROWSE_INITIAL_SIZE; + rt->capacity = UA_REFTREE_INITIAL_SIZE; return UA_STATUSCODE_GOOD; } -static void +void RefTree_clear(RefTree *rt) { for(size_t i = 0; i < rt->size; i++) UA_ExpandedNodeId_clear(&rt->targets[i]); @@ -32481,6 +35065,9 @@ RefTree_double(RefTree *rt) { return UA_STATUSCODE_BADOUTOFMEMORY; /* Repair the pointers for the realloced array+tree */ + // What is this sorcery? + // FIXME: This needs some cleaning up or explanation. + // IMO uintptr could be completely avoided here. uintptr_t arraydiff = (uintptr_t)newTargets - (uintptr_t)rt->targets; RefEntry *reArray = (RefEntry*) ((uintptr_t)newTargets + (capacity * sizeof(UA_ExpandedNodeId))); @@ -32499,20 +35086,26 @@ RefTree_double(RefTree *rt) { reArray[i].target = (UA_ExpandedNodeId*)((uintptr_t)reArray[i].target + arraydiff); } - rt->head.zip_root = (RefEntry*)((uintptr_t)rt->head.zip_root + entrydiff); + ZIP_ROOT(&rt->head) = (RefEntry*)((uintptr_t)ZIP_ROOT(&rt->head) + entrydiff); rt->capacity = capacity; rt->targets = newTargets; return UA_STATUSCODE_GOOD; } -static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT -RefTree_add(RefTree *rt, const UA_ExpandedNodeId *target) { +static UA_StatusCode +RefTree_add(RefTree *rt, UA_NodePointer target, UA_Boolean *duplicate) { + UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(target); + /* Is the target already in the tree? */ RefEntry dummy; - dummy.target = target; - dummy.targetHash = UA_ExpandedNodeId_hash(target); - if(ZIP_FIND(RefHead, &rt->head, &dummy)) + memset(&dummy, 0, sizeof(RefEntry)); + dummy.target = &en; + dummy.targetHash = UA_ExpandedNodeId_hash(&en); + if(ZIP_FIND(RefHead, &rt->head, &dummy)) { + if(duplicate) + *duplicate = true; return UA_STATUSCODE_GOOD; + } UA_StatusCode s = UA_STATUSCODE_GOOD; if(rt->capacity <= rt->size) { @@ -32520,7 +35113,7 @@ RefTree_add(RefTree *rt, const UA_ExpandedNodeId *target) { if(s != UA_STATUSCODE_GOOD) return s; } - s = UA_ExpandedNodeId_copy(target, &rt->targets[rt->size]); + s = UA_ExpandedNodeId_copy(&en, &rt->targets[rt->size]); if(s != UA_STATUSCODE_GOOD) return s; RefEntry *re = (RefEntry*)((uintptr_t)rt->targets + @@ -32528,34 +35121,65 @@ RefTree_add(RefTree *rt, const UA_ExpandedNodeId *target) { (sizeof(RefEntry) * rt->size)); re->target = &rt->targets[rt->size]; re->targetHash = dummy.targetHash; - ZIP_INSERT(RefHead, &rt->head, re, ZIP_FFS32(UA_UInt32_random())); + ZIP_INSERT(RefHead, &rt->head, re, UA_UInt32_random()); rt->size++; return UA_STATUSCODE_GOOD; } -static UA_Boolean -relevantReference(const UA_NodeId *refType, size_t relevantRefsSize, - const UA_NodeId *relevantRefs) { - if(!relevantRefs) - return true; - for(size_t i = 0; i < relevantRefsSize; i++) { - if(UA_NodeId_equal(refType, &relevantRefs[i])) - return true; - } - return false; +UA_StatusCode +RefTree_addNodeId(RefTree *rt, const UA_NodeId *target, + UA_Boolean *duplicate) { + return RefTree_add(rt, UA_NodePointer_fromNodeId(target), duplicate); +} + +UA_Boolean +RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target) { + RefEntry dummy; + dummy.target = target; + dummy.targetHash = UA_ExpandedNodeId_hash(target); + return !!ZIP_FIND(RefHead, &rt->head, &dummy); +} + +UA_Boolean +RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target) { + UA_ExpandedNodeId en; + en.nodeId = *target; + en.namespaceUri = UA_STRING_NULL; + en.serverIndex = 0; + return RefTree_contains(rt, &en); } +/********************/ +/* Browse Recursive */ +/********************/ + static UA_StatusCode -addRelevantReferences(UA_Server *server, RefTree *rt, const UA_NodeId *nodeId, - size_t refTypesSize, const UA_NodeId *refTypes, - UA_BrowseDirection browseDirection) { - const UA_Node *node = UA_NODESTORE_GET(server, nodeId); +browseRecursiveInner(UA_Server *server, RefTree *rt, UA_UInt16 depth, UA_Boolean skip, + UA_NodePointer nodeP, UA_BrowseDirection browseDirection, + const UA_ReferenceTypeSet *refTypes, UA_UInt32 nodeClassMask) { + /* Have we reached the max recursion depth? */ + if(depth >= UA_MAX_TREE_RECURSE) + return UA_STATUSCODE_GOOD; + + const UA_Node *node = UA_NODESTORE_GETFROMREF(server, nodeP); if(!node) return UA_STATUSCODE_BADNODEIDUNKNOWN; UA_StatusCode retval = UA_STATUSCODE_GOOD; - for(size_t i = 0; i < node->referencesSize; i++) { - UA_NodeReferenceKind *rk = &node->references[i]; + const UA_NodeHead *head = &node->head; + + /* Add the current node to the results if we don't want to skip it (i.e. for + * includeStartNodes) and it matches the nodeClassMask filter. Process the + * children also if the nodeClassMask does not match. */ + if(!skip && matchClassMask(node, nodeClassMask)) { + UA_Boolean duplicate = false; + retval = RefTree_addNodeId(rt, &head->nodeId, &duplicate); + if(duplicate || retval != UA_STATUSCODE_GOOD) + goto cleanup; + } + + for(size_t i = 0; i < head->referencesSize; i++) { + UA_NodeReferenceKind *rk = &head->references[i]; /* Reference in the right direction? */ if(rk->isInverse && browseDirection == UA_BROWSEDIRECTION_FORWARD) @@ -32564,11 +35188,18 @@ addRelevantReferences(UA_Server *server, RefTree *rt, const UA_NodeId *nodeId, continue; /* Is the reference part of the hierarchy of references we look for? */ - if(!relevantReference(&rk->referenceTypeId, refTypesSize, refTypes)) + if(!UA_ReferenceTypeSet_contains(refTypes, rk->referenceTypeIndex)) continue; - for(size_t k = 0; k < rk->refTargetsSize; k++) { - retval = RefTree_add(rt, &rk->refTargets[k].targetId); + const UA_ReferenceTarget *target = NULL; + while((target = UA_NodeReferenceKind_iterate(rk, target))) { + if(UA_NodePointer_isLocal(target->targetId)) { + retval = browseRecursiveInner(server, rt, (UA_UInt16)(depth+1), false, + target->targetId, browseDirection, + refTypes, nodeClassMask); + } else { + retval = RefTree_add(rt, target->targetId, NULL); + } if(retval != UA_STATUSCODE_GOOD) goto cleanup; } @@ -32580,133 +35211,63 @@ addRelevantReferences(UA_Server *server, RefTree *rt, const UA_NodeId *nodeId, } UA_StatusCode -browseRecursive(UA_Server *server, - size_t startNodesSize, const UA_NodeId *startNodes, - size_t refTypesSize, const UA_NodeId *refTypes, - UA_BrowseDirection browseDirection, UA_Boolean includeStartNodes, +browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes, + UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes, + UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes, size_t *resultsSize, UA_ExpandedNodeId **results) { RefTree rt; UA_StatusCode retval = RefTree_init(&rt); if(retval != UA_STATUSCODE_GOOD) return retval; - /* Add the start nodes? */ - UA_ExpandedNodeId en = UA_EXPANDEDNODEID_NULL; - for(size_t i = 0; i < startNodesSize && retval == UA_STATUSCODE_GOOD; i++) { - if(includeStartNodes) { - en.nodeId = startNodes[i]; - retval = RefTree_add(&rt, &en); - } else { - retval = addRelevantReferences(server, &rt, &startNodes[i], - refTypesSize, refTypes, browseDirection); - } - } - if(retval != UA_STATUSCODE_GOOD) { - RefTree_clear(&rt); - return retval; - } - - /* Loop over the targets we have so far. This recurses, as new targets are - * added to rt. */ - for(size_t i = 0; i < rt.size; i++) { - /* Dont recurse into remote nodes */ - if(rt.targets[i].serverIndex > 0) - continue; - if(rt.targets[i].namespaceUri.data != NULL) - continue; - - retval = addRelevantReferences(server, &rt, &rt.targets[i].nodeId, - refTypesSize, refTypes, browseDirection); - if(retval != UA_STATUSCODE_GOOD) { - RefTree_clear(&rt); - return retval; - } + for(size_t i = 0; i < startNodesSize; i++) { + /* Call the inner recursive browse separately for the search direction. + * Otherwise we might take one step up and another step down in the + * search tree. */ + if(browseDirection == UA_BROWSEDIRECTION_FORWARD || + browseDirection == UA_BROWSEDIRECTION_BOTH) + retval |= browseRecursiveInner(server, &rt, 0, !includeStartNodes, + UA_NodePointer_fromNodeId(&startNodes[i]), + UA_BROWSEDIRECTION_FORWARD, + refTypes, nodeClassMask); + if(browseDirection == UA_BROWSEDIRECTION_INVERSE || + browseDirection == UA_BROWSEDIRECTION_BOTH) + retval |= browseRecursiveInner(server, &rt, 0, !includeStartNodes, + UA_NodePointer_fromNodeId(&startNodes[i]), + UA_BROWSEDIRECTION_INVERSE, + refTypes, nodeClassMask); + if(retval != UA_STATUSCODE_GOOD) + break; } - if(rt.size > 0) { + if(rt.size > 0 && retval == UA_STATUSCODE_GOOD) { *results = rt.targets; *resultsSize = rt.size; } else { RefTree_clear(&rt); } - - return UA_STATUSCODE_GOOD; -} - -/* Only if IncludeSubtypes is selected */ -UA_StatusCode -referenceSubtypes(UA_Server *server, const UA_NodeId *refType, - size_t *refTypesSize, UA_NodeId **refTypes) { - /* Leave refTypes == NULL */ - if(UA_NodeId_isNull(refType)) - return UA_STATUSCODE_GOOD; - - /* Browse recursive for the hierarchy of sub-references */ - UA_ExpandedNodeId *rt = NULL; - size_t rtSize = 0; - UA_NodeId hasSubtype = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); - UA_StatusCode retval = browseRecursive(server, 1, refType, 1, &hasSubtype, - UA_BROWSEDIRECTION_FORWARD, true, &rtSize, &rt); - if(retval != UA_STATUSCODE_GOOD) - return retval; - - UA_assert(rtSize > 0); - - /* Allocate space (realloc if non-NULL) */ - UA_NodeId *newRt = NULL; - if(!*refTypes) { - newRt = (UA_NodeId*)UA_malloc(rtSize * UA_TYPES[UA_TYPES_NODEID].memSize); - } else { - newRt = (UA_NodeId*)UA_realloc(*refTypes, (*refTypesSize + rtSize) * - UA_TYPES[UA_TYPES_NODEID].memSize); - } - if(!newRt) { - UA_Array_delete(rt, rtSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - *refTypes = newRt; - - /* Move NodeIds */ - for(size_t i = 0; i < rtSize; i++) { - (*refTypes)[*refTypesSize + i] = rt[i].nodeId; - UA_NodeId_init(&rt[i].nodeId); - } - *refTypesSize += rtSize; - UA_Array_delete(rt, rtSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); - return UA_STATUSCODE_GOOD; + return retval; } UA_StatusCode UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd, size_t *resultsSize, UA_ExpandedNodeId **results) { + UA_LOCK(&server->serviceMutex); + /* Set the list of relevant reference types */ - UA_LOCK(server->serviceMutex); - UA_NodeId *refTypes = NULL; - size_t refTypesSize = 0; - UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(!UA_NodeId_isNull(&bd->referenceTypeId)) { - if(!bd->includeSubtypes) { - refTypes = (UA_NodeId*)(uintptr_t)&bd->referenceTypeId; - refTypesSize = 1; - } else { - retval = referenceSubtypes(server, &bd->referenceTypeId, - &refTypesSize, &refTypes); - if(retval != UA_STATUSCODE_GOOD) { - UA_UNLOCK(server->serviceMutex); - return retval; - } - } + UA_ReferenceTypeSet refTypes; + UA_StatusCode retval = referenceTypeIndices(server, &bd->referenceTypeId, + &refTypes, bd->includeSubtypes); + if(retval != UA_STATUSCODE_GOOD) { + UA_UNLOCK(&server->serviceMutex); + return retval; } /* Browse */ - retval = browseRecursive(server, 1, &bd->nodeId, refTypesSize, refTypes, - bd->browseDirection, false, resultsSize, results); + retval = browseRecursive(server, 1, &bd->nodeId, bd->browseDirection, + &refTypes, bd->nodeClassMask, false, resultsSize, results); - /* Clean up */ - if(refTypes && bd->includeSubtypes) - UA_Array_delete(refTypes, refTypesSize, &UA_TYPES[UA_TYPES_NODEID]); - - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -32724,10 +35285,10 @@ static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT RefResult_init(RefResult *rr) { memset(rr, 0, sizeof(RefResult)); rr->descr = (UA_ReferenceDescription*) - UA_Array_new(UA_BROWSE_INITIAL_SIZE, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]); + UA_Array_new(UA_REFTREE_INITIAL_SIZE, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]); if(!rr->descr) return UA_STATUSCODE_BADOUTOFMEMORY; - rr->capacity = UA_BROWSE_INITIAL_SIZE; + rr->capacity = UA_REFTREE_INITIAL_SIZE; rr->size = 0; return UA_STATUSCODE_GOOD; } @@ -32756,30 +35317,30 @@ RefResult_clear(RefResult *rr) { struct ContinuationPoint { ContinuationPoint *next; UA_ByteString identifier; + + /* Parameters of the Browse Request */ UA_BrowseDescription browseDescription; UA_UInt32 maxReferences; + UA_ReferenceTypeSet relevantReferences; - size_t relevantReferencesSize; - UA_NodeId *relevantReferences; - - /* The last point in the node references? */ - size_t referenceKindIndex; - size_t targetIndex; + /* The next target to be transmitted to the client */ + UA_ExpandedNodeId nextTarget; + UA_Byte nextRefKindIndex; }; ContinuationPoint * ContinuationPoint_clear(ContinuationPoint *cp) { UA_ByteString_clear(&cp->identifier); UA_BrowseDescription_clear(&cp->browseDescription); - UA_Array_delete(cp->relevantReferences, cp->relevantReferencesSize, - &UA_TYPES[UA_TYPES_NODEID]); + UA_ExpandedNodeId_clear(&cp->nextTarget); return cp->next; } /* Target node on top of the stack */ static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT -addReferenceDescription(UA_Server *server, RefResult *rr, const UA_NodeReferenceKind *ref, - UA_UInt32 mask, const UA_ExpandedNodeId *nodeId, const UA_Node *curr) { +addReferenceDescription(UA_Server *server, RefResult *rr, + const UA_NodeReferenceKind *ref, UA_UInt32 mask, + UA_NodePointer nodeP, const UA_Node *curr) { /* Ensure capacity is left */ UA_StatusCode retval = UA_STATUSCODE_GOOD; if(rr->size >= rr->capacity) { @@ -32791,9 +35352,13 @@ addReferenceDescription(UA_Server *server, RefResult *rr, const UA_NodeReference UA_ReferenceDescription *descr = &rr->descr[rr->size]; /* Fields without access to the actual node */ - retval = UA_ExpandedNodeId_copy(nodeId, &descr->nodeId); - if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID) - retval |= UA_NodeId_copy(&ref->referenceTypeId, &descr->referenceTypeId); + UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(nodeP); + retval = UA_ExpandedNodeId_copy(&en, &descr->nodeId); + if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID) { + const UA_NodeId *refTypeId = + UA_NODESTORE_GETREFERENCETYPEID(server, ref->referenceTypeIndex); + retval |= UA_NodeId_copy(refTypeId, &descr->referenceTypeId); + } if(mask & UA_BROWSERESULTMASK_ISFORWARD) descr->isForward = !ref->isInverse; @@ -32805,17 +35370,17 @@ addReferenceDescription(UA_Server *server, RefResult *rr, const UA_NodeReference /* Fields that require the actual node */ if(mask & UA_BROWSERESULTMASK_NODECLASS) - retval |= UA_NodeClass_copy(&curr->nodeClass, &descr->nodeClass); + descr->nodeClass = curr->head.nodeClass; if(mask & UA_BROWSERESULTMASK_BROWSENAME) - retval |= UA_QualifiedName_copy(&curr->browseName, &descr->browseName); + retval |= UA_QualifiedName_copy(&curr->head.browseName, &descr->browseName); if(mask & UA_BROWSERESULTMASK_DISPLAYNAME) - retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName); + retval |= UA_LocalizedText_copy(&curr->head.displayName, &descr->displayName); if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION) { - if(curr->nodeClass == UA_NODECLASS_OBJECT || - curr->nodeClass == UA_NODECLASS_VARIABLE) { - const UA_Node *type = getNodeType(server, curr); + if(curr->head.nodeClass == UA_NODECLASS_OBJECT || + curr->head.nodeClass == UA_NODECLASS_VARIABLE) { + const UA_Node *type = getNodeType(server, &curr->head); if(type) { - retval |= UA_NodeId_copy(&type->nodeId, &descr->typeDefinition.nodeId); + retval |= UA_NodeId_copy(&type->head.nodeId, &descr->typeDefinition.nodeId); UA_NODESTORE_RELEASE(server, type); } } @@ -32828,29 +35393,51 @@ addReferenceDescription(UA_Server *server, RefResult *rr, const UA_NodeReference return retval; } -static UA_Boolean -matchClassMask(const UA_Node *node, UA_UInt32 nodeClassMask) { - if(nodeClassMask != UA_NODECLASS_UNSPECIFIED && - (node->nodeClass & nodeClassMask) == 0) - return false; - return true; -} - /* Returns whether the node / continuationpoint is done */ static UA_StatusCode -browseReferences(UA_Server *server, const UA_Node *node, +browseReferences(UA_Server *server, const UA_NodeHead *head, ContinuationPoint *cp, RefResult *rr, UA_Boolean *done) { - UA_assert(cp != NULL); - const UA_BrowseDescription *bd= &cp->browseDescription; + UA_assert(cp); + const UA_BrowseDescription *bd = &cp->browseDescription; - size_t referenceKindIndex = cp->referenceKindIndex; - size_t targetIndex = cp->targetIndex; + size_t i = 0; + const UA_ReferenceTarget *ref = NULL; + + /* If the cp was previously used, skip forward to the next ReferenceType to + * be transmitted. */ + if(cp->identifier.length > 0) { + for(; i < head->referencesSize; ++i) { + UA_NodeReferenceKind *rk = &head->references[i]; + + /* Was this the last transmitted ReferenceType? */ + if(head->references[i].referenceTypeIndex != cp->nextRefKindIndex) + continue; - /* Loop over the node's references */ - const UA_Node *target = NULL; + /* Reference in the right direction? */ + if(rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_FORWARD) + continue; + if(!rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_INVERSE) + continue; + + /* Get the next target */ + ref = UA_NodeReferenceKind_findTarget(rk, &cp->nextTarget); + if(ref) + break; + + /* The target no longer exists for this ReferenceType (and + * direction). Continue to iterate for the case that a nodestore has + * a duplicate UA_NodeReferenceKind (should not happen though). */ + } + + /* Fail with an error if the reference no longer exists. */ + if(!ref) + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Loop over the ReferenceTypes */ UA_StatusCode retval = UA_STATUSCODE_GOOD; - for(; referenceKindIndex < node->referencesSize; ++referenceKindIndex) { - UA_NodeReferenceKind *rk = &node->references[referenceKindIndex]; + for(; i < head->referencesSize; ++i) { + UA_NodeReferenceKind *rk = &head->references[i]; /* Reference in the right direction? */ if(rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_FORWARD) @@ -32859,46 +35446,48 @@ browseReferences(UA_Server *server, const UA_Node *node, continue; /* Is the reference part of the hierarchy of references we look for? */ - if(!relevantReference(&rk->referenceTypeId, cp->relevantReferencesSize, - cp->relevantReferences)) + if(!UA_ReferenceTypeSet_contains(&cp->relevantReferences, + rk->referenceTypeIndex)) continue; - /* Loop over the targets */ - for(; targetIndex < rk->refTargetsSize; ++targetIndex) { - target = NULL; + /* We have a matching ReferenceType! */ + /* Loop over the targets for the ReferenceType. Start with the first + * entry if we don't have a known entry-point from the cp. */ + if(!ref) + ref = UA_NodeReferenceKind_iterate(rk, ref); + for(;ref; ref = UA_NodeReferenceKind_iterate(rk, ref)) { /* Get the node if it is not a remote reference */ - if(rk->refTargets[targetIndex].targetId.serverIndex == 0 && - rk->refTargets[targetIndex].targetId.namespaceUri.data == NULL) { - target = UA_NODESTORE_GET(server, - &rk->refTargets[targetIndex].targetId.nodeId); - - /* Test if the node class matches */ - if(target && !matchClassMask(target, bd->nodeClassMask)) { - if(target) - UA_NODESTORE_RELEASE(server, target); - continue; - } + const UA_Node *target = + UA_NODESTORE_GETFROMREF(server, ref->targetId); + + /* Test if the node class matches */ + if(target && !matchClassMask(target, bd->nodeClassMask)) { + UA_NODESTORE_RELEASE(server, target); + continue; } - /* A match! Did we reach maxrefs? */ + /* We have a matching target! */ + + /* Reached maxrefs. Update the cp and bail. */ if(rr->size >= cp->maxReferences) { - cp->referenceKindIndex = referenceKindIndex; - cp->targetIndex = targetIndex; if(target) UA_NODESTORE_RELEASE(server, target); - return UA_STATUSCODE_GOOD; + cp->nextRefKindIndex = rk->referenceTypeIndex; + /* Make a deep copy */ + UA_ExpandedNodeId tmpEn = + UA_NodePointer_toExpandedNodeId(ref->targetId); + return UA_ExpandedNodeId_copy(&tmpEn, &cp->nextTarget); } /* Copy the node description. Target is on top of the stack */ retval = addReferenceDescription(server, rr, rk, bd->resultMask, - &rk->refTargets[targetIndex].targetId, target); - UA_NODESTORE_RELEASE(server, target); + ref->targetId, target); + if(target) + UA_NODESTORE_RELEASE(server, target); if(retval != UA_STATUSCODE_GOOD) return retval; } - - targetIndex = 0; /* Start at index 0 for the next reference kind */ } /* The node is done */ @@ -32913,6 +35502,7 @@ browseReferences(UA_Server *server, const UA_Node *node, static UA_Boolean browseWithContinuation(UA_Server *server, UA_Session *session, ContinuationPoint *cp, UA_BrowseResult *result) { + UA_assert(cp); const UA_BrowseDescription *descr = &cp->browseDescription; /* Is the browsedirection valid? */ @@ -32931,7 +35521,7 @@ browseWithContinuation(UA_Server *server, UA_Session *session, return true; } - UA_Boolean isRef = (reftype->nodeClass == UA_NODECLASS_REFERENCETYPE); + UA_Boolean isRef = (reftype->head.nodeClass == UA_NODECLASS_REFERENCETYPE); UA_NODESTORE_RELEASE(server, reftype); if(!isRef) { @@ -32947,9 +35537,10 @@ browseWithContinuation(UA_Server *server, UA_Session *session, } if(session != &server->adminSession && - !server->config.accessControl.allowBrowseNode(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, - &descr->nodeId, node->context)) { + !server->config.accessControl. + allowBrowseNode(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + &descr->nodeId, node->head.context)) { result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED; UA_NODESTORE_RELEASE(server, node); return true; @@ -32964,7 +35555,7 @@ browseWithContinuation(UA_Server *server, UA_Session *session, /* Browse the references */ UA_Boolean done = false; - result->statusCode = browseReferences(server, node, cp, &rr, &done); + result->statusCode = browseReferences(server, &node->head, cp, &rr, &done); UA_NODESTORE_RELEASE(server, node); if(result->statusCode != UA_STATUSCODE_GOOD) { RefResult_clear(&rr); @@ -32989,48 +35580,37 @@ void Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxrefs, const UA_BrowseDescription *descr, UA_BrowseResult *result) { /* Stack-allocate a temporary cp */ - UA_STACKARRAY(ContinuationPoint, cp, 1); - memset(cp, 0, sizeof(ContinuationPoint)); - cp->maxReferences = *maxrefs; - cp->browseDescription = *descr; /* Shallow copy. Deep-copy later if we persist the cp. */ + ContinuationPoint cp; + memset(&cp, 0, sizeof(ContinuationPoint)); + cp.maxReferences = *maxrefs; + cp.browseDescription = *descr; /* Shallow copy. Deep-copy later if we persist the cp. */ /* How many references can we return at most? */ - if(cp->maxReferences == 0) { + if(cp.maxReferences == 0) { if(server->config.maxReferencesPerNode != 0) { - cp->maxReferences = server->config.maxReferencesPerNode; + cp.maxReferences = server->config.maxReferencesPerNode; } else { - cp->maxReferences = UA_INT32_MAX; + cp.maxReferences = UA_INT32_MAX; } } else { if(server->config.maxReferencesPerNode != 0 && - cp->maxReferences > server->config.maxReferencesPerNode) { - cp->maxReferences= server->config.maxReferencesPerNode; + cp.maxReferences > server->config.maxReferencesPerNode) { + cp.maxReferences= server->config.maxReferencesPerNode; } } /* Get the list of relevant reference types */ - if(!UA_NodeId_isNull(&descr->referenceTypeId)) { - if(!descr->includeSubtypes) { - cp->relevantReferences = (UA_NodeId*)(uintptr_t)&descr->referenceTypeId; - cp->relevantReferencesSize = 1; - } else { - result->statusCode = - referenceSubtypes(server, &descr->referenceTypeId, - &cp->relevantReferencesSize, &cp->relevantReferences); - if(result->statusCode != UA_STATUSCODE_GOOD) - return; - } - } + result->statusCode = + referenceTypeIndices(server, &descr->referenceTypeId, + &cp.relevantReferences, descr->includeSubtypes); + if(result->statusCode != UA_STATUSCODE_GOOD) + return; - UA_Boolean done = browseWithContinuation(server, session, cp, result); + UA_Boolean done = browseWithContinuation(server, session, &cp, result); /* Exit early if done or an error occurred */ - if(done || result->statusCode != UA_STATUSCODE_GOOD) { - if(descr->includeSubtypes) - UA_Array_delete(cp->relevantReferences, cp->relevantReferencesSize, - &UA_TYPES[UA_TYPES_NODEID]); + if(done || result->statusCode != UA_STATUSCODE_GOOD) return; - } /* Persist the new continuation point */ @@ -33039,7 +35619,7 @@ Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxref UA_StatusCode retval = UA_STATUSCODE_GOOD; /* Enough space for the continuation point? */ - if(session->availableContinuationPoints <= 0) { + if(session->availableContinuationPoints == 0) { retval = UA_STATUSCODE_BADNOCONTINUATIONPOINTS; goto cleanup; } @@ -33050,26 +35630,16 @@ Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxref retval = UA_STATUSCODE_BADOUTOFMEMORY; goto cleanup; } - memset(cp2, 0, sizeof(ContinuationPoint)); - cp2->referenceKindIndex = cp->referenceKindIndex; - cp2->targetIndex = cp->targetIndex; - cp2->maxReferences = cp->maxReferences; - if(descr->includeSubtypes) { - cp2->relevantReferences = cp->relevantReferences; - cp2->relevantReferencesSize = cp->relevantReferencesSize; - } else { - retval = UA_Array_copy(cp->relevantReferences, cp->relevantReferencesSize, - (void**)&cp2->relevantReferences, &UA_TYPES[UA_TYPES_NODEID]); - if(retval != UA_STATUSCODE_GOOD) - goto cleanup; - cp2->relevantReferencesSize = cp->relevantReferencesSize; - } - - /* Copy the description */ + memset(cp2, 0, sizeof(ContinuationPoint)); + /* The BrowseDescription is only a shallow copy in cp */ retval = UA_BrowseDescription_copy(descr, &cp2->browseDescription); if(retval != UA_STATUSCODE_GOOD) goto cleanup; + cp2->maxReferences = cp.maxReferences; + cp2->relevantReferences = cp.relevantReferences; + cp2->nextTarget = cp.nextTarget; + cp2->nextRefKindIndex = cp.nextRefKindIndex; /* Create a random bytestring via a Guid */ ident = UA_Guid_new(); @@ -33104,7 +35674,7 @@ Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxref void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request, UA_BrowseResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing BrowseRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Test the number of operations in the request */ if(server->config.maxNodesPerBrowse != 0 && @@ -33120,10 +35690,13 @@ void Service_Browse(UA_Server *server, UA_Session *session, } response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_Browse, + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_Browse, &request->requestedMaxReferencesPerNode, - &request->nodesToBrowseSize, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], - &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSERESULT]); + &request->nodesToBrowseSize, + &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], + &response->resultsSize, + &UA_TYPES[UA_TYPES_BROWSERESULT]); } UA_BrowseResult @@ -33131,9 +35704,9 @@ UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences, const UA_BrowseDescription *bd) { UA_BrowseResult result; UA_BrowseResult_init(&result); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Operation_Browse(server, &server->adminSession, &maxReferences, bd, &result); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return result; } @@ -33142,7 +35715,8 @@ Operation_BrowseNext(UA_Server *server, UA_Session *session, const UA_Boolean *releaseContinuationPoints, const UA_ByteString *continuationPoint, UA_BrowseResult *result) { /* Find the continuation point */ - ContinuationPoint **prev = &session->continuationPoints, *cp; + ContinuationPoint **prev = &session->continuationPoints; + ContinuationPoint *cp; while((cp = *prev)) { if(UA_ByteString_equal(&cp->identifier, continuationPoint)) break; @@ -33171,7 +35745,8 @@ Operation_BrowseNext(UA_Server *server, UA_Session *session, ++session->availableContinuationPoints; } else { /* Return the cp identifier */ - UA_StatusCode retval = UA_ByteString_copy(&cp->identifier, &result->continuationPoint); + UA_StatusCode retval = + UA_ByteString_copy(&cp->identifier, &result->continuationPoint); if(retval != UA_STATUSCODE_GOOD) { UA_BrowseResult_clear(result); result->statusCode = retval; @@ -33185,14 +35760,18 @@ Service_BrowseNext(UA_Server *server, UA_Session *session, UA_BrowseNextResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing BrowseNextRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); - UA_Boolean releaseContinuationPoints = request->releaseContinuationPoints; /* request is const */ + UA_Boolean releaseContinuationPoints = + request->releaseContinuationPoints; /* request is const */ response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_BrowseNext, + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_BrowseNext, &releaseContinuationPoints, - &request->continuationPointsSize, &UA_TYPES[UA_TYPES_BYTESTRING], - &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSERESULT]); + &request->continuationPointsSize, + &UA_TYPES[UA_TYPES_BYTESTRING], + &response->resultsSize, + &UA_TYPES[UA_TYPES_BROWSERESULT]); } UA_BrowseResult @@ -33200,10 +35779,10 @@ UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, const UA_ByteString *continuationPoint) { UA_BrowseResult result; UA_BrowseResult_init(&result); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Operation_BrowseNext(server, &server->adminSession, &releaseContinuationPoint, continuationPoint, &result); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return result; } @@ -33211,46 +35790,50 @@ UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, /* TranslateBrowsePath */ /***********************/ +/* Find all entries for that hash. There are duplicate for the possible hash + * collisions. The exact browsename is checked afterwards. */ static UA_StatusCode -addBrowseTarget(RefTree *next, const UA_ReferenceTarget *rt) { +recursiveAddBrowseHashTarget(RefTree *results, struct aa_head *head, + const UA_ReferenceTarget *rt) { UA_assert(rt); - UA_StatusCode res = RefTree_add(next, &rt->targetId); - UA_ReferenceTarget *left = ZIP_LEFT(rt, nameTreeFields); - if(left && left->targetNameHash == rt->targetNameHash) - res |= addBrowseTarget(next, left); - UA_ReferenceTarget *right = ZIP_RIGHT(rt, nameTreeFields); - if(right && right->targetNameHash == rt->targetNameHash) - res |= addBrowseTarget(next, right); + UA_StatusCode res = RefTree_add(results, rt->targetId, NULL); + UA_ReferenceTarget *prev = (UA_ReferenceTarget*)aa_prev(head, rt); + while(prev && prev->targetNameHash == rt->targetNameHash) { + res |= RefTree_add(results, prev->targetId, NULL); + prev = (UA_ReferenceTarget*)aa_prev(head, prev); + } + UA_ReferenceTarget *next= (UA_ReferenceTarget*)aa_next(head, rt); + while(next && next->targetNameHash == rt->targetNameHash) { + res |= RefTree_add(results, next->targetId, NULL); + next = (UA_ReferenceTarget*)aa_next(head, next); + } return res; } static UA_StatusCode walkBrowsePathElement(UA_Server *server, UA_Session *session, - const UA_RelativePath *path, const size_t pathIndex, UA_UInt32 nodeClassMask, - const UA_QualifiedName *lastBrowseName, UA_BrowsePathResult *result, - RefTree *current, RefTree *next) { + const UA_RelativePath *path, const size_t pathIndex, + UA_UInt32 nodeClassMask, const UA_QualifiedName *lastBrowseName, + UA_BrowsePathResult *result, RefTree *current, RefTree *next) { /* For the next level. Note the difference from lastBrowseName */ const UA_RelativePathElement *elem = &path->elements[pathIndex]; UA_UInt32 browseNameHash = UA_QualifiedName_hash(&elem->targetName); - /* Is the ReferenceType valid? */ - UA_Boolean all_refs = UA_NodeId_isNull(&elem->referenceTypeId); - if(!all_refs) { - const UA_Node *rootRef = UA_NODESTORE_GET(server, &elem->referenceTypeId); - if(!rootRef) - return UA_STATUSCODE_BADNOMATCH; - UA_Boolean match = (rootRef->nodeClass == UA_NODECLASS_REFERENCETYPE); - UA_NODESTORE_RELEASE(server, rootRef); - if(!match) - return UA_STATUSCODE_BADNOMATCH; - } + /* Get the relevant ReferenceTypes */ + UA_ReferenceTypeSet refTypes; + UA_StatusCode res = + referenceTypeIndices(server, &elem->referenceTypeId, + &refTypes, elem->includeSubtypes); + if(res != UA_STATUSCODE_GOOD) + return UA_STATUSCODE_BADNOMATCH; - /* Loop over all Nodes int the current depth level */ - UA_StatusCode res = UA_STATUSCODE_GOOD; + struct aa_head _refNameTree = refNameTree; + + /* Loop over all Nodes in the current depth level */ for(size_t i = 0; i < current->size; i++) { - /* Remote Node. Immediately add to the results with the RemainingPathIndex set. */ - if(current->targets[i].serverIndex > 0 || - current->targets[i].namespaceUri.length > 0) { + /* Remote Node. Immediately add to the results with the + * RemainingPathIndex set. */ + if(!UA_ExpandedNodeId_isLocal(¤t->targets[i])) { /* Increase the size of the results array */ UA_BrowsePathTarget *tmpResults = (UA_BrowsePathTarget*) UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) * @@ -33277,9 +35860,10 @@ walkBrowsePathElement(UA_Server *server, UA_Session *session, /* Test whether the node fits the class mask */ UA_Boolean skip = !matchClassMask(node, nodeClassMask); - /* Does the BrowseName match for the current node (not the rerences + /* Does the BrowseName match for the current node (not the references * going out here) */ - skip |= (lastBrowseName && !UA_QualifiedName_equal(lastBrowseName, &node->browseName)); + skip |= (lastBrowseName && + !UA_QualifiedName_equal(lastBrowseName, &node->head.browseName)); if(skip) { UA_NODESTORE_RELEASE(server, node); @@ -33287,36 +35871,45 @@ walkBrowsePathElement(UA_Server *server, UA_Session *session, } /* Loop over the ReferenceKinds */ - for(size_t j = 0; j < node->referencesSize; j++) { - UA_NodeReferenceKind *rk = &node->references[j]; + for(size_t j = 0; j < node->head.referencesSize; j++) { + UA_NodeReferenceKind *rk = &node->head.references[j]; /* Does the direction of the reference match? */ if(rk->isInverse != elem->isInverse) continue; /* Does the reference type match? */ - if(!all_refs) { - if(!elem->includeSubtypes) { - if(!UA_NodeId_equal(&rk->referenceTypeId, &elem->referenceTypeId)) - continue; - } else { - UA_Boolean match = - isNodeInTree(server, &rk->referenceTypeId, - &elem->referenceTypeId, &subtypeId, 1); - if(!match) + if(!UA_ReferenceTypeSet_contains(&refTypes, rk->referenceTypeIndex)) + continue; + + if(rk->hasRefTree) { + /* Retrieve by BrowseName hash. We might have several nodes where + * the hash matches. The exact BrowseName will be verified in the + * next iteration of the outer loop. So we only have to retrieve + * every node just once. */ + _refNameTree.root = rk->targets.tree.nameTreeRoot; + UA_ReferenceTarget *rt = (UA_ReferenceTarget*) + aa_find(&_refNameTree, &browseNameHash); + if(!rt) + continue; + + res = recursiveAddBrowseHashTarget(next, &_refNameTree, rt); + if(res != UA_STATUSCODE_GOOD) + break; + } else { + /* The array entries don't have a BrowseName hash. Add all of + * them at this level to be checked with a full string + * comparison. */ + for(size_t k = 0; k < rk->targetsSize; k++) { + if(rk->targets.array[k].targetNameHash != browseNameHash) continue; + res = RefTree_add(next, rk->targets.array[k].targetId, NULL); + if(res != UA_STATUSCODE_GOOD) + break; } + if(res != UA_STATUSCODE_GOOD) + break; } - - /* Retrieve by BrowseName hash */ - UA_ReferenceTarget *rt = ZIP_FIND(UA_ReferenceTargetNameTree, - &rk->refTargetsNameTree, &browseNameHash); - if(!rt) - continue; - - res = addBrowseTarget(next, rt); - if(res != UA_STATUSCODE_GOOD) - break; } UA_NODESTORE_RELEASE(server, node); @@ -33329,9 +35922,9 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, const UA_UInt32 *nodeClassMask, const UA_BrowsePath *path, UA_BrowsePathResult *result) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); - if(path->relativePath.elementsSize <= 0) { + if(path->relativePath.elementsSize == 0) { result->statusCode = UA_STATUSCODE_BADNOTHINGTODO; return; } @@ -33353,23 +35946,25 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, UA_NODESTORE_RELEASE(server, startingNode); /* Create two RefTrees that are alternated between path elements */ - RefTree rt1, rt2, *current = &rt1, *next = &rt2, *tmp; + RefTree rt1; + RefTree rt2; + RefTree *current = &rt1; + RefTree *next = &rt2; + RefTree *tmp; result->statusCode |= RefTree_init(&rt1); result->statusCode |= RefTree_init(&rt2); + UA_BrowsePathTarget *tmpResults = NULL; + UA_QualifiedName *browseNameFilter = NULL; if(result->statusCode != UA_STATUSCODE_GOOD) goto cleanup; /* Copy the starting node into next */ - UA_ExpandedNodeId startingNodeId; - UA_ExpandedNodeId_init(&startingNodeId); - startingNodeId.nodeId = path->startingNode; - result->statusCode = RefTree_add(next, &startingNodeId); + result->statusCode = RefTree_addNodeId(next, &path->startingNode, NULL); if(result->statusCode != UA_STATUSCODE_GOOD) goto cleanup; /* Walk the path elements. Retrieve the nodes only once from the NodeStore. * Hence the BrowseName is checked with one element "delay". */ - UA_QualifiedName *browseNameFilter = NULL; for(size_t i = 0; i < path->relativePath.elementsSize; i++) { /* Switch the trees */ tmp = current; @@ -33398,10 +35993,10 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, } /* Allocate space for the results array */ - UA_BrowsePathTarget *tmpResults = (UA_BrowsePathTarget*) + tmpResults = (UA_BrowsePathTarget*) UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) * (result->targetsSize + next->size)); - if(!tmpResults) { + if(!tmpResults && next->size > 0) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; goto cleanup; } @@ -33412,7 +36007,7 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, const UA_Node *node = UA_NODESTORE_GET(server, &next->targets[k].nodeId); if(!node) continue; - UA_Boolean match = UA_QualifiedName_equal(browseNameFilter, &node->browseName); + UA_Boolean match = UA_QualifiedName_equal(browseNameFilter, &node->head.browseName); UA_NODESTORE_RELEASE(server, node); if(!match) continue; @@ -33445,7 +36040,7 @@ Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, UA_BrowsePathResult translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_BrowsePathResult result; UA_BrowsePathResult_init(&result); UA_UInt32 nodeClassMask = 0; /* All node classes */ @@ -33457,9 +36052,9 @@ translateBrowsePathToNodeIds(UA_Server *server, UA_BrowsePathResult UA_Server_translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_BrowsePathResult result = translateBrowsePathToNodeIds(server, browsePath); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return result; } @@ -33469,7 +36064,7 @@ Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session, UA_TranslateBrowsePathsToNodeIdsResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing TranslateBrowsePathsToNodeIdsRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Test the number of operations in the request */ if(server->config.maxNodesPerTranslateBrowsePathsToNodeIds != 0 && @@ -33490,13 +36085,23 @@ Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session, UA_BrowsePathResult browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, size_t browsePathSize, const UA_QualifiedName *browsePath) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + UA_BrowsePathResult bpr; + UA_BrowsePathResult_init(&bpr); + if(browsePathSize > UA_MAX_TREE_RECURSE) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Simplified Browse Path too long"); + bpr.statusCode = UA_STATUSCODE_BADINTERNALERROR; + return bpr; + } /* Construct the BrowsePath */ UA_BrowsePath bp; UA_BrowsePath_init(&bp); bp.startingNode = origin; - UA_STACKARRAY(UA_RelativePathElement, rpe, browsePathSize); + + UA_RelativePathElement rpe[UA_MAX_TREE_RECURSE]; memset(rpe, 0, sizeof(UA_RelativePathElement) * browsePathSize); for(size_t j = 0; j < browsePathSize; j++) { rpe[j].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); @@ -33507,12 +36112,7 @@ browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, bp.relativePath.elementsSize = browsePathSize; /* Browse */ - UA_BrowsePathResult bpr; - UA_BrowsePathResult_init(&bpr); - UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE; -#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS - nodeClassMask |= UA_NODECLASS_OBJECTTYPE; -#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ + UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_OBJECTTYPE; Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, &nodeClassMask, &bp, &bpr); return bpr; @@ -33521,9 +36121,9 @@ browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, UA_BrowsePathResult UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, size_t browsePathSize, const UA_QualifiedName *browsePath) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, origin, browsePathSize, browsePath); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return bpr; } @@ -33536,7 +36136,7 @@ void Service_RegisterNodes(UA_Server *server, UA_Session *session, UA_RegisterNodesResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing RegisterNodesRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); //TODO: hang the nodeids to the session if really needed if(request->nodesToRegisterSize == 0) { @@ -33563,7 +36163,7 @@ void Service_UnregisterNodes(UA_Server *server, UA_Session *session, UA_UnregisterNodesResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing UnRegisterNodesRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); //TODO: remove the nodeids from the session if really needed if(request->nodesToUnregisterSize == 0) @@ -33577,7 +36177,7 @@ void Service_UnregisterNodes(UA_Server *server, UA_Session *session, } } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_method.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_method.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -33598,27 +36198,24 @@ void Service_UnregisterNodes(UA_Server *server, UA_Session *session, #ifdef UA_ENABLE_METHODCALLS /* conditional compilation */ static const UA_VariableNode * -getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod, +getArgumentsVariableNode(UA_Server *server, const UA_NodeHead *head, UA_String withBrowseName) { - UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); - for(size_t i = 0; i < ofMethod->referencesSize; ++i) { - UA_NodeReferenceKind *rk = &ofMethod->references[i]; - + for(size_t i = 0; i < head->referencesSize; ++i) { + const UA_NodeReferenceKind *rk = &head->references[i]; if(rk->isInverse != false) continue; - - if(!UA_NodeId_equal(&hasProperty, &rk->referenceTypeId)) + if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASPROPERTY) continue; - - for(size_t j = 0; j < rk->refTargetsSize; ++j) { + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { const UA_Node *refTarget = - UA_NODESTORE_GET(server, &rk->refTargets[j].targetId.nodeId); + UA_NODESTORE_GETFROMREF(server, t->targetId); if(!refTarget) continue; - if(refTarget->nodeClass == UA_NODECLASS_VARIABLE && - refTarget->browseName.namespaceIndex == 0 && - UA_String_equal(&withBrowseName, &refTarget->browseName.name)) { - return (const UA_VariableNode*)refTarget; + if(refTarget->head.nodeClass == UA_NODECLASS_VARIABLE && + refTarget->head.browseName.namespaceIndex == 0 && + UA_String_equal(&withBrowseName, &refTarget->head.browseName.name)) { + return &refTarget->variableNode; } UA_NODESTORE_RELEASE(server, refTarget); } @@ -33653,10 +36250,20 @@ typeCheckArguments(UA_Server *server, UA_Session *session, /* Type-check every argument against the definition */ UA_StatusCode retval = UA_STATUSCODE_GOOD; UA_Argument *argReqs = (UA_Argument*)argRequirements->value.data.value.value.data; + const char *reason; for(size_t i = 0; i < argReqsSize; ++i) { + if(compatibleValue(server, session, &argReqs[i].dataType, argReqs[i].valueRank, + argReqs[i].arrayDimensionsSize, argReqs[i].arrayDimensions, + &args[i], NULL, &reason)) + continue; + + /* Incompatible value. Try to correct the type if possible. */ + adjustValueType(server, &args[i], &argReqs[i].dataType); + + /* Recheck */ if(!compatibleValue(server, session, &argReqs[i].dataType, argReqs[i].valueRank, argReqs[i].arrayDimensionsSize, argReqs[i].arrayDimensions, - &args[i], NULL)) { + &args[i], NULL, &reason)) { inputArgumentResults[i] = UA_STATUSCODE_BADTYPEMISMATCH; retval = UA_STATUSCODE_BADINVALIDARGUMENT; } @@ -33671,7 +36278,7 @@ validMethodArguments(UA_Server *server, UA_Session *session, const UA_MethodNode UA_StatusCode *inputArgumentResults) { /* Get the input arguments node */ const UA_VariableNode *inputArguments = - getArgumentsVariableNode(server, method, UA_STRING("InputArguments")); + getArgumentsVariableNode(server, &method->head, UA_STRING("InputArguments")); if(!inputArguments) { if(request->inputArgumentsSize > 0) return UA_STATUSCODE_BADTOOMANYARGUMENTS; @@ -33679,10 +36286,9 @@ validMethodArguments(UA_Server *server, UA_Session *session, const UA_MethodNode } /* Verify the request */ - UA_StatusCode retval = typeCheckArguments(server, session, inputArguments, - request->inputArgumentsSize, - request->inputArguments, - inputArgumentResults); + UA_StatusCode retval = + typeCheckArguments(server, session, inputArguments, request->inputArgumentsSize, + request->inputArguments, inputArgumentResults); /* Release the input arguments node */ UA_NODESTORE_RELEASE(server, (const UA_Node*)inputArguments); @@ -33690,7 +36296,6 @@ validMethodArguments(UA_Server *server, UA_Session *session, const UA_MethodNode } static const UA_NodeId hasComponentNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}; -static const UA_NodeId hasSubTypeNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}}; static const UA_NodeId organizedByNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}}; static const UA_String namespaceDiModel = UA_STRING_STATIC("http://opcfoundation.org/UA/DI/"); static const UA_NodeId hasTypeDefinitionNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASTYPEDEFINITION}}; @@ -33702,14 +36307,14 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request, UA_CallMethodResult *result, const UA_MethodNode *method, const UA_ObjectNode *object) { /* Verify the object's NodeClass */ - if(object->nodeClass != UA_NODECLASS_OBJECT && - object->nodeClass != UA_NODECLASS_OBJECTTYPE) { + if(object->head.nodeClass != UA_NODECLASS_OBJECT && + object->head.nodeClass != UA_NODECLASS_OBJECTTYPE) { result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; return; } /* Verify the method's NodeClass */ - if(method->nodeClass != UA_NODECLASS_METHOD) { + if(method->head.nodeClass != UA_NODECLASS_METHOD) { result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; return; } @@ -33720,20 +36325,28 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, return; } + UA_NodePointer methodP = UA_NodePointer_fromNodeId(&request->methodId); + /* Verify method/object relations. Object must have a hasComponent or a * subtype of hasComponent reference to the method node. Therefore, check * every reference between the parent object and the method node if there is * a hasComponent (or subtype) reference */ + UA_ReferenceTypeSet hasComponentRefs; + result->statusCode = + referenceTypeIndices(server, &hasComponentNodeId, &hasComponentRefs, true); + if(result->statusCode != UA_STATUSCODE_GOOD) + return; + UA_Boolean found = false; - for(size_t i = 0; i < object->referencesSize && !found; ++i) { - UA_NodeReferenceKind *rk = &object->references[i]; + for(size_t i = 0; i < object->head.referencesSize && !found; ++i) { + const UA_NodeReferenceKind *rk = &object->head.references[i]; if(rk->isInverse) continue; - if(!isNodeInTree(server, &rk->referenceTypeId, - &hasComponentNodeId, &hasSubTypeNodeId, 1)) + if(!UA_ReferenceTypeSet_contains(&hasComponentRefs, rk->referenceTypeIndex)) continue; - for(size_t j = 0; j < rk->refTargetsSize; ++j) { - if(UA_NodeId_equal(&rk->refTargets[j].targetId.nodeId, &request->methodId)) { + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + if(UA_NodePointer_equal(t->targetId, methodP)) { found = true; break; } @@ -33761,35 +36374,48 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, } functionGroupNodeId.namespaceIndex = (UA_UInt16)foundNamespace; + UA_ReferenceTypeSet hasTypeDefinitionRefs; + result->statusCode = + referenceTypeIndices(server, &hasTypeDefinitionNodeId, + &hasTypeDefinitionRefs, true); + if(result->statusCode != UA_STATUSCODE_GOOD) + return; + /* Search for a HasTypeDefinition (or sub-) reference in the parent object */ - for(size_t i = 0; i < object->referencesSize && !found; ++i) { - UA_NodeReferenceKind *rk = &object->references[i]; + for(size_t i = 0; i < object->head.referencesSize && !found; ++i) { + const UA_NodeReferenceKind *rk = &object->head.references[i]; if(rk->isInverse) continue; - if(!isNodeInTree(server, &rk->referenceTypeId, - &hasTypeDefinitionNodeId, &hasSubTypeNodeId, 1)) + if(!UA_ReferenceTypeSet_contains(&hasTypeDefinitionRefs, rk->referenceTypeIndex)) continue; /* Verify that the HasTypeDefinition is equal to FunctionGroupType * (or sub-type) from the DI model */ - for(size_t j = 0; j < rk->refTargetsSize && !found; ++j) { - if(!isNodeInTree(server, &rk->refTargets[j].targetId.nodeId, - &functionGroupNodeId, &hasSubTypeNodeId, 1)) + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + if(!UA_NodePointer_isLocal(t->targetId)) continue; + UA_NodeId tmpId = UA_NodePointer_toNodeId(t->targetId); + if(!isNodeInTree_singleRef(server, &tmpId, &functionGroupNodeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) + continue; + /* Search for the called method with reference Organize (or * sub-type) from the parent object */ - for(size_t k = 0; k < object->referencesSize && !found; ++k) { - UA_NodeReferenceKind *rkInner = &object->references[k]; + for(size_t k = 0; k < object->head.referencesSize && !found; ++k) { + const UA_NodeReferenceKind *rkInner = &object->head.references[k]; if(rkInner->isInverse) continue; - if(!isNodeInTree(server, &rkInner->referenceTypeId, - &organizedByNodeId, &hasSubTypeNodeId, 1)) + const UA_NodeId * refId = + UA_NODESTORE_GETREFERENCETYPEID(server, rkInner->referenceTypeIndex); + if(!isNodeInTree_singleRef(server, refId, &organizedByNodeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) continue; - for(size_t m = 0; m < rkInner->refTargetsSize; ++m) { - if(UA_NodeId_equal(&rkInner->refTargets[m].targetId.nodeId, - &request->methodId)) { + const UA_ReferenceTarget *t2 = NULL; + while((t2 = UA_NodeReferenceKind_iterate(rkInner, t2))) { + if(UA_NodePointer_equal(t2->targetId, methodP)) { found = true; break; } @@ -33806,12 +36432,12 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, /* Verify access rights */ UA_Boolean executable = method->executable; if(session != &server->adminSession) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); executable = executable && server->config.accessControl. getUserExecutableOnObject(server, &server->config.accessControl, &session->sessionId, - session->sessionHandle, &request->methodId, method->context, - &request->objectId, object->context); - UA_LOCK(server->serviceMutex); + session->sessionHandle, &request->methodId, method->head.context, + &request->objectId, object->head.context); + UA_LOCK(&server->serviceMutex); } if(!executable) { @@ -33829,7 +36455,8 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, result->inputArgumentResultsSize = request->inputArgumentsSize; /* Verify Input Arguments */ - result->statusCode = validMethodArguments(server, session, method, request, result->inputArgumentResults); + result->statusCode = validMethodArguments(server, session, method, request, + result->inputArgumentResults); /* Return inputArgumentResults only for BADINVALIDARGUMENT */ if(result->statusCode != UA_STATUSCODE_BADINVALIDARGUMENT) { @@ -33845,7 +36472,7 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, /* Get the output arguments node */ const UA_VariableNode *outputArguments = - getArgumentsVariableNode(server, method, UA_STRING("OutputArguments")); + getArgumentsVariableNode(server, &method->head, UA_STRING("OutputArguments")); /* Allocate the output arguments array */ size_t outputArgsSize = 0; @@ -33863,13 +36490,13 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session, UA_NODESTORE_RELEASE(server, (const UA_Node*)outputArguments); /* Call the method */ - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); result->statusCode = method->method(server, &session->sessionId, session->sessionHandle, - &method->nodeId, method->context, - &object->nodeId, object->context, + &method->head.nodeId, method->head.context, + &object->head.nodeId, object->head.context, request->inputArgumentsSize, request->inputArguments, result->outputArgumentsSize, result->outputArguments); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); /* TODO: Verify Output matches the argument definition */ } @@ -33881,25 +36508,24 @@ Operation_CallMethodAsync(UA_Server *server, UA_Session *session, UA_UInt32 requ UA_CallMethodRequest *opRequest, UA_CallMethodResult *opResult, UA_AsyncResponse **ar) { /* Get the method node */ - const UA_MethodNode *method = (const UA_MethodNode*) - UA_NODESTORE_GET(server, &opRequest->methodId); + const UA_Node *method = UA_NODESTORE_GET(server, &opRequest->methodId); if(!method) { opResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN; return; } /* Get the object node */ - const UA_ObjectNode *object = (const UA_ObjectNode*) - UA_NODESTORE_GET(server, &opRequest->objectId); + const UA_Node *object = UA_NODESTORE_GET(server, &opRequest->objectId); if(!object) { opResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN; - UA_NODESTORE_RELEASE(server, (const UA_Node*)method); + UA_NODESTORE_RELEASE(server, method); return; } /* Synchronous execution */ - if(!method->async) { - callWithMethodAndObject(server, session, opRequest, opResult, method, object); + if(!method->methodNode.async) { + callWithMethodAndObject(server, session, opRequest, opResult, + &method->methodNode, &object->objectNode); goto cleanup; } @@ -33909,9 +36535,8 @@ Operation_CallMethodAsync(UA_Server *server, UA_Session *session, UA_UInt32 requ if(!*ar) { opResult->statusCode = UA_AsyncManager_createAsyncResponse(&server->asyncManager, server, - &session->sessionId, requestId, - requestHandle, UA_ASYNCOPERATIONTYPE_CALL, - ar); + &session->sessionId, requestId, requestHandle, + UA_ASYNCOPERATIONTYPE_CALL, ar); if(opResult->statusCode != UA_STATUSCODE_GOOD) goto cleanup; } @@ -33923,8 +36548,8 @@ Operation_CallMethodAsync(UA_Server *server, UA_Session *session, UA_UInt32 requ cleanup: /* Release the method and object node */ - UA_NODESTORE_RELEASE(server, (const UA_Node*)method); - UA_NODESTORE_RELEASE(server, (const UA_Node*)object); + UA_NODESTORE_RELEASE(server, method); + UA_NODESTORE_RELEASE(server, object); } void @@ -33941,23 +36566,21 @@ Service_CallAsync(UA_Server *server, UA_Session *session, UA_UInt32 requestId, UA_AsyncResponse *ar = NULL; response->responseHeader.serviceResult = UA_Server_processServiceOperationsAsync(server, session, requestId, - request->requestHeader.requestHandle, - (UA_AsyncServiceOperation)Operation_CallMethodAsync, - &request->methodsToCallSize, - &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], - &response->resultsSize, - &UA_TYPES[UA_TYPES_CALLMETHODRESULT], &ar); + request->requestHeader.requestHandle, + (UA_AsyncServiceOperation)Operation_CallMethodAsync, + &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], + &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT], &ar); if(ar) { if(ar->opCountdown > 0) { - /* Move all results to the AsyncResponse. The async operation results - * will be overwritten when the workers return results. */ + /* Move all results to the AsyncResponse. The async operation + * results will be overwritten when the workers return results. */ ar->response.callResponse = *response; UA_CallResponse_init(response); *finished = false; } else { - /* If there is a new AsyncResponse, ensure it has at least one pending - * operation */ + /* If there is a new AsyncResponse, ensure it has at least one + * pending operation */ UA_AsyncManager_removeAsyncResponse(&server->asyncManager, ar); } } @@ -33968,35 +36591,33 @@ static void Operation_CallMethod(UA_Server *server, UA_Session *session, void *context, const UA_CallMethodRequest *request, UA_CallMethodResult *result) { /* Get the method node */ - const UA_MethodNode *method = (const UA_MethodNode*) - UA_NODESTORE_GET(server, &request->methodId); + const UA_Node *method = UA_NODESTORE_GET(server, &request->methodId); if(!method) { result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN; return; } /* Get the object node */ - const UA_ObjectNode *object = (const UA_ObjectNode*) - UA_NODESTORE_GET(server, &request->objectId); + const UA_Node *object = UA_NODESTORE_GET(server, &request->objectId); if(!object) { result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN; - UA_NODESTORE_RELEASE(server, (const UA_Node*)method); + UA_NODESTORE_RELEASE(server, method); return; } /* Continue with method and object as context */ - callWithMethodAndObject(server, session, request, result, method, object); + callWithMethodAndObject(server, session, request, result, + &method->methodNode, &object->objectNode); /* Release the method and object node */ - UA_NODESTORE_RELEASE(server, (const UA_Node*)method); - UA_NODESTORE_RELEASE(server, (const UA_Node*)object); + UA_NODESTORE_RELEASE(server, method); + UA_NODESTORE_RELEASE(server, object); } void Service_Call(UA_Server *server, UA_Session *session, - const UA_CallRequest *request, - UA_CallResponse *response) { + const UA_CallRequest *request, UA_CallResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing CallRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxNodesPerMethodCall != 0 && request->methodsToCallSize > server->config.maxNodesPerMethodCall) { @@ -34005,24 +36626,25 @@ void Service_Call(UA_Server *server, UA_Session *session, } response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_CallMethod, NULL, - &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], - &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]); + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_CallMethod, NULL, + &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], + &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]); } -UA_CallMethodResult UA_EXPORT +UA_CallMethodResult UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) { UA_CallMethodResult result; UA_CallMethodResult_init(&result); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Operation_CallMethod(server, &server->adminSession, NULL, request, &result); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return result; } #endif /* UA_ENABLE_METHODCALLS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_session.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_session.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -34043,9 +36665,9 @@ UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) { /* Delayed callback to free the session memory */ static void removeSessionCallback(UA_Server *server, session_list_entry *entry) { - UA_LOCK(server->serviceMutex); - UA_Session_deleteMembersCleanup(&entry->session, server); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_Session_clear(&entry->session, server); + UA_UNLOCK(&server->serviceMutex); } void @@ -34053,57 +36675,59 @@ UA_Server_removeSession(UA_Server *server, session_list_entry *sentry, UA_DiagnosticEvent event) { UA_Session *session = &sentry->session; - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Remove the Subscriptions */ #ifdef UA_ENABLE_SUBSCRIPTIONS UA_Subscription *sub, *tempsub; - LIST_FOREACH_SAFE(sub, &session->serverSubscriptions, listEntry, tempsub) { - UA_Session_deleteSubscription(server, session, sub->subscriptionId); + TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) { + UA_Subscription_delete(server, sub); } UA_PublishResponseEntry *entry; while((entry = UA_Session_dequeuePublishReq(session))) { - UA_PublishResponse_deleteMembers(&entry->response); + UA_PublishResponse_clear(&entry->response); UA_free(entry); } #endif /* Callback into userland access control */ if(server->config.accessControl.closeSession) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); server->config.accessControl.closeSession(server, &server->config.accessControl, &session->sessionId, session->sessionHandle); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); } /* Detach the Session from the SecureChannel */ UA_Session_detachFromSecureChannel(session); /* Deactivate the session */ - sentry->session.activated = false; + if(sentry->session.activated) { + sentry->session.activated = false; + server->activeSessionCount--; + } /* Detach the session from the session manager and make the capacity * available */ LIST_REMOVE(sentry, pointers); - UA_atomic_subUInt32(&server->sessionCount, 1); - UA_atomic_subSize(&server->serverStats.ss.currentSessionCount, 1); + server->sessionCount--; switch(event) { case UA_DIAGNOSTICEVENT_CLOSE: case UA_DIAGNOSTICEVENT_PURGE: break; case UA_DIAGNOSTICEVENT_TIMEOUT: - UA_atomic_addSize(&server->serverStats.ss.sessionTimeoutCount, 1); + server->serverDiagnosticsSummary.sessionTimeoutCount++; break; case UA_DIAGNOSTICEVENT_REJECT: - UA_atomic_addSize(&server->serverStats.ss.rejectedSessionCount, 1); + server->serverDiagnosticsSummary.rejectedSessionCount++; break; case UA_DIAGNOSTICEVENT_SECURITYREJECT: - UA_atomic_addSize(&server->serverStats.ss.securityRejectedSessionCount, 1); + server->serverDiagnosticsSummary.securityRejectedSessionCount++; break; case UA_DIAGNOSTICEVENT_ABORT: - UA_atomic_addSize(&server->serverStats.ss.sessionAbortCount, 1); + server->serverDiagnosticsSummary.sessionAbortCount++; break; default: UA_assert(false); @@ -34115,13 +36739,15 @@ UA_Server_removeSession(UA_Server *server, session_list_entry *sentry, sentry->cleanupCallback.callback = (UA_ApplicationCallback)removeSessionCallback; sentry->cleanupCallback.application = server; sentry->cleanupCallback.data = sentry; - UA_WorkQueue_enqueueDelayed(&server->workQueue, &sentry->cleanupCallback); + sentry->cleanupCallback.nextTime = UA_DateTime_nowMonotonic() + 1; + sentry->cleanupCallback.interval = 0; /* Remove the structure */ + UA_Timer_addTimerEntry(&server->timer, &sentry->cleanupCallback, NULL); } UA_StatusCode UA_Server_removeSessionByToken(UA_Server *server, const UA_NodeId *token, UA_DiagnosticEvent event) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); session_list_entry *entry; LIST_FOREACH(entry, &server->sessions, pointers) { if(UA_NodeId_equal(&entry->session.header.authenticationToken, token)) { @@ -34134,7 +36760,7 @@ UA_Server_removeSessionByToken(UA_Server *server, const UA_NodeId *token, void UA_Server_cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); session_list_entry *sentry, *temp; LIST_FOREACH_SAFE(sentry, &server->sessions, pointers, temp) { /* Session has timed out? */ @@ -34151,7 +36777,7 @@ UA_Server_cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic) { UA_Session * getSessionByToken(UA_Server *server, const UA_NodeId *token) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); session_list_entry *current = NULL; LIST_FOREACH(current, &server->sessions, pointers) { @@ -34174,7 +36800,7 @@ getSessionByToken(UA_Server *server, const UA_NodeId *token) { UA_Session * UA_Server_getSessionById(UA_Server *server, const UA_NodeId *sessionId) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); session_list_entry *current = NULL; LIST_FOREACH(current, &server->sessions, pointers) { @@ -34208,7 +36834,7 @@ signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel, /* Prepare the signature */ size_t signatureSize = securityPolicy->certificateSigningAlgorithm. - getLocalSignatureSize(securityPolicy, channel->channelContext); + getLocalSignatureSize(channel->channelContext); UA_StatusCode retval = UA_String_copy(&securityPolicy->certificateSigningAlgorithm.uri, &signatureData->algorithm); retval |= UA_ByteString_allocBuffer(&signatureData->signature, signatureSize); @@ -34227,7 +36853,7 @@ signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel, memcpy(dataToSign.data + request->clientCertificate.length, request->clientNonce.data, request->clientNonce.length); retval = securityPolicy->certificateSigningAlgorithm. - sign(securityPolicy, channel->channelContext, &dataToSign, &signatureData->signature); + sign(channel->channelContext, &dataToSign, &signatureData->signature); /* Clean up */ UA_ByteString_clear(&dataToSign); @@ -34238,32 +36864,38 @@ signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel, UA_StatusCode UA_Server_createSession(UA_Server *server, UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_Session **session) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); - if(server->sessionCount >= server->config.maxSessions) + if(server->sessionCount >= server->config.maxSessions) { + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "Could not create a Session - Server limits reached"); return UA_STATUSCODE_BADTOOMANYSESSIONS; + } - session_list_entry *newentry = (session_list_entry *)UA_malloc(sizeof(session_list_entry)); + session_list_entry *newentry = (session_list_entry*) + UA_malloc(sizeof(session_list_entry)); if(!newentry) return UA_STATUSCODE_BADOUTOFMEMORY; - UA_atomic_addUInt32(&server->sessionCount, 1); + /* Initialize the Session */ UA_Session_init(&newentry->session); newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random()); newentry->session.header.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random()); + newentry->session.timeout = server->config.maxSessionTimeout; if(request->requestedSessionTimeout <= server->config.maxSessionTimeout && request->requestedSessionTimeout > 0) newentry->session.timeout = request->requestedSessionTimeout; - else - newentry->session.timeout = server->config.maxSessionTimeout; /* Attach the session to the channel. But don't activate for now. */ if(channel) UA_Session_attachToSecureChannel(&newentry->session, channel); UA_Session_updateLifetime(&newentry->session); + /* Add to the server */ LIST_INSERT_HEAD(&server->sessions, newentry, pointers); + server->sessionCount++; + *session = &newentry->session; return UA_STATUSCODE_GOOD; } @@ -34272,7 +36904,7 @@ void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_CreateSessionResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, "Trying to create session"); if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || @@ -34311,8 +36943,8 @@ Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, "The client's ApplicationURI did not match the certificate"); - UA_atomic_addSize(&server->serverStats.ss.securityRejectedSessionCount, 1); - UA_atomic_addSize(&server->serverStats.ss.rejectedSessionCount, 1); + server->serverDiagnosticsSummary.securityRejectedSessionCount++; + server->serverDiagnosticsSummary.rejectedSessionCount++; return; } } @@ -34323,6 +36955,7 @@ Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, "Processing CreateSessionRequest failed"); + server->serverDiagnosticsSummary.rejectedSessionCount++; return; } @@ -34372,6 +37005,13 @@ Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, response->responseHeader.serviceResult |= UA_String_copy(&request->sessionName, &newSession->sessionName); +#ifdef UA_ENABLE_DIAGNOSTICS + response->responseHeader.serviceResult |= + UA_String_copy(&request->serverUri, &newSession->diagnostics.serverUri); + response->responseHeader.serviceResult |= + UA_String_copy(&request->endpointUrl, &newSession->diagnostics.endpointUrl); +#endif + UA_ByteString_init(&response->serverCertificate); if(server->config.endpointsSize > 0) @@ -34404,45 +37044,48 @@ Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, return; } - UA_LOG_INFO_CHANNEL(&server->config.logger, channel, - "Session " UA_PRINTF_GUID_FORMAT " created", - UA_PRINTF_GUID_DATA(newSession->sessionId.identifier.guid)); +#ifdef UA_ENABLE_DIAGNOSTICS + newSession->diagnostics.clientConnectionTime = UA_DateTime_now(); + newSession->diagnostics.clientLastContactTime = + newSession->diagnostics.clientConnectionTime; + + /* Create the object in the information model */ + createSessionObject(server, newSession); +#endif + + UA_LOG_INFO_SESSION(&server->config.logger, newSession, "Session created"); } static UA_StatusCode -checkSignature(const UA_Server *server, const UA_SecureChannel *channel, - UA_Session *session, const UA_ActivateSessionRequest *request) { - if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && - channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) - return UA_STATUSCODE_GOOD; - - /* Check for zero signature length in client signature */ - if(request->clientSignature.signature.length == 0) +checkSignature(const UA_Server *server, const UA_SecurityPolicy *securityPolicy, + void *channelContext, const UA_ByteString *serverNonce, + const UA_SignatureData *signature) { + /* Check for zero signature length */ + if(signature->signature.length == 0) return UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID; - if(!channel->securityPolicy) + if(!securityPolicy) return UA_STATUSCODE_BADINTERNALERROR; - const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; const UA_ByteString *localCertificate = &securityPolicy->localCertificate; - + /* Data to verify is calculated by appending the serverNonce to the local certificate */ UA_ByteString dataToVerify; - size_t dataToVerifySize = localCertificate->length + session->serverNonce.length; + size_t dataToVerifySize = localCertificate->length + serverNonce->length; UA_StatusCode retval = UA_ByteString_allocBuffer(&dataToVerify, dataToVerifySize); if(retval != UA_STATUSCODE_GOOD) return retval; memcpy(dataToVerify.data, localCertificate->data, localCertificate->length); memcpy(dataToVerify.data + localCertificate->length, - session->serverNonce.data, session->serverNonce.length); + serverNonce->data, serverNonce->length); retval = securityPolicy->certificateSigningAlgorithm. - verify(securityPolicy, channel->channelContext, &dataToVerify, - &request->clientSignature.signature); + verify(channelContext, &dataToVerify, &signature->signature); UA_ByteString_clear(&dataToVerify); return retval; } #ifdef UA_ENABLE_ENCRYPTION + static UA_StatusCode decryptPassword(UA_SecurityPolicy *securityPolicy, void *tempChannelContext, const UA_ByteString *serverNonce, UA_UserNameIdentityToken *userToken) { @@ -34453,15 +37096,15 @@ decryptPassword(UA_SecurityPolicy *securityPolicy, void *tempChannelContext, UA_UInt32 tokenSecretLength; UA_ByteString decryptedTokenSecret, tokenServerNonce; + size_t tokenpos = 0; + size_t offset = 0; if(UA_ByteString_copy(&userToken->password, &decryptedTokenSecret) != UA_STATUSCODE_GOOD) return UA_STATUSCODE_BADIDENTITYTOKENINVALID; UA_StatusCode retval = UA_STATUSCODE_BADIDENTITYTOKENINVALID; - if(asymEnc->decrypt(securityPolicy, tempChannelContext, - &decryptedTokenSecret) != UA_STATUSCODE_GOOD) + if(asymEnc->decrypt(tempChannelContext, &decryptedTokenSecret) != UA_STATUSCODE_GOOD) goto cleanup; - size_t offset = 0; UA_UInt32_decodeBinary(&decryptedTokenSecret, &offset, &tokenSecretLength); /* The decrypted data must be large enough to include the Encrypted Token @@ -34481,7 +37124,7 @@ decryptPassword(UA_SecurityPolicy *securityPolicy, void *tempChannelContext, /* The server nonce must match according to the 1.04.1 specification errata, * chapter 3. */ - size_t tokenpos = sizeof(UA_UInt32) + tokenSecretLength - serverNonce->length; + tokenpos = sizeof(UA_UInt32) + tokenSecretLength - serverNonce->length; tokenServerNonce.length = serverNonce->length; tokenServerNonce.data = &decryptedTokenSecret.data[tokenpos]; if(!UA_ByteString_equal(serverNonce, &tokenServerNonce)) @@ -34567,6 +37210,42 @@ selectEndpointAndTokenPolicy(UA_Server *server, UA_SecureChannel *channel, } } +#ifdef UA_ENABLE_DIAGNOSTICS +static UA_StatusCode +saveClientUserId(const UA_ExtensionObject *userIdentityToken, + UA_SessionSecurityDiagnosticsDataType *diag) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + + UA_String_clear(&diag->clientUserIdOfSession); + if(userIdentityToken->encoding != UA_EXTENSIONOBJECT_DECODED) + return UA_STATUSCODE_GOOD; + + if(userIdentityToken->content.decoded.type == + &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) { + /* String of length 0 */ + } else if(userIdentityToken->content.decoded.type == + &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) { + const UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken*) + userIdentityToken->content.decoded.data; + res = UA_String_copy(&userToken->userName, &diag->clientUserIdOfSession); + } else if(userIdentityToken->content.decoded.type == + &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) { + /* TODO: return the X509 Subject Name of the certificate */ + } else { + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + } + + if(res != UA_STATUSCODE_GOOD) + return res; + + return UA_Array_appendCopy((void**)&diag->clientUserIdHistory, + &diag->clientUserIdHistorySize, + &diag->clientUserIdOfSession, + &UA_TYPES[UA_TYPES_STRING]); +} +#endif + + /* TODO: Check all of the following: The Server shall verify that the * Certificate the Client used to create the new SecureChannel is the same as * the Certificate used to create the original SecureChannel. In addition, the @@ -34579,7 +37258,10 @@ void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, const UA_ActivateSessionRequest *request, UA_ActivateSessionResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + const UA_EndpointDescription *ed = NULL; + const UA_UserTokenPolicy *utp = NULL; + UA_String *tmpLocaleIds; + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_Session *session = getSessionByToken(server, &request->requestHeader.authenticationToken); if(!session) { @@ -34610,19 +37292,21 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, goto rejected; } - /* Check if the signature corresponds to the ServerNonce that was last sent - * to the client */ - response->responseHeader.serviceResult = checkSignature(server, channel, session, request); - if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_SESSION(&server->config.logger, session, - "ActivateSession: Signature check failed with StatusCode %s", - UA_StatusCode_name(response->responseHeader.serviceResult)); - goto securityRejected; + /* Check the client signature */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + response->responseHeader.serviceResult = + checkSignature(server, channel->securityPolicy, channel->channelContext, + &session->serverNonce, &request->clientSignature); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "ActivateSession: Client signature check failed with StatusCode %s", + UA_StatusCode_name(response->responseHeader.serviceResult)); + goto securityRejected; + } } /* Find the matching Endpoint with UserTokenPolicy */ - const UA_EndpointDescription *ed = NULL; - const UA_UserTokenPolicy *utp = NULL; selectEndpointAndTokenPolicy(server, channel, &request->userIdentityToken, &ed, &utp); if(!ed) { response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID; @@ -34638,12 +37322,12 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, * policy of the secure channel is used. */ UA_SecurityPolicy* securityPolicy; if(!utp->securityPolicyUri.data) - securityPolicy = UA_SecurityPolicy_getSecurityPolicyByUri(server, &ed->securityPolicyUri); + securityPolicy = getSecurityPolicyByUri(server, &ed->securityPolicyUri); else - securityPolicy = UA_SecurityPolicy_getSecurityPolicyByUri(server, &utp->securityPolicyUri); + securityPolicy = getSecurityPolicyByUri(server, &utp->securityPolicyUri); if(!securityPolicy) { response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; - goto rejected; + goto securityRejected; } /* Test if the encryption algorithm is correctly specified */ @@ -34660,21 +37344,22 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, * used for the password from the SecureChannel */ void *tempChannelContext = channel->channelContext; if(securityPolicy != channel->securityPolicy) { - /* TODO: This is a hack. We use our own certificate to create a - * channel context. Because the client does not provide one in a - * #None SecureChannel. We should not need a ChannelContext at all - * for asymmetric decryption where the remote certificate is not + /* We use our own certificate to create a temporary channel + * context. Because the client does not provide one in a #None + * SecureChannel. We should not need a ChannelContext at all for + * asymmetric decryption where the remote certificate is not * used. */ - response->responseHeader.serviceResult = - securityPolicy->channelModule. + UA_UNLOCK(&server->serviceMutex); + response->responseHeader.serviceResult = securityPolicy->channelModule. newContext(securityPolicy, &securityPolicy->localCertificate, &tempChannelContext); + UA_LOCK(&server->serviceMutex); if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_LOG_WARNING_SESSION(&server->config.logger, session, "ActivateSession: " "Failed to create a context for the SecurityPolicy %.*s", (int)securityPolicy->policyUri.length, securityPolicy->policyUri.data); - goto rejected; + goto securityRejected; } } @@ -34683,8 +37368,15 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, decryptPassword(securityPolicy, tempChannelContext, &session->serverNonce, userToken); /* Remove the temporary channel context */ - if(securityPolicy != channel->securityPolicy) + if(securityPolicy != channel->securityPolicy) { + UA_UNLOCK(&server->serviceMutex); securityPolicy->channelModule.deleteContext(tempChannelContext); + UA_LOCK(&server->serviceMutex); + } + } else if(userToken->encryptionAlgorithm.length != 0) { + /* If SecurityPolicy is None there shall be no EncryptionAlgorithm */ + response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID; + goto securityRejected; } if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { @@ -34696,16 +37388,72 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, #endif } +#ifdef UA_ENABLE_ENCRYPTION + /* If it is a X509IdentityToken, check the userTokenSignature. Note this + * only validates that the user has the corresponding private key for the + * given user cetificate. Checking whether the user certificate is trusted + * has to be implemented in the access control plugin. The entire token is + * forwarded in the call to ActivateSession. */ + if(utp->tokenType == UA_USERTOKENTYPE_CERTIFICATE) { + UA_X509IdentityToken* userCertToken = (UA_X509IdentityToken*) + request->userIdentityToken.content.decoded.data; + + /* If the userTokenPolicy doesn't specify a security policy the security + * policy of the secure channel is used. */ + UA_SecurityPolicy* securityPolicy; + if(!utp->securityPolicyUri.data) + securityPolicy = getSecurityPolicyByUri(server, &ed->securityPolicyUri); + else + securityPolicy = getSecurityPolicyByUri(server, &utp->securityPolicyUri); + if(!securityPolicy) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + goto securityRejected; + } + + /* We need a channel context with the user certificate in order to reuse + * the signature checking code. */ + void *tempChannelContext; + UA_UNLOCK(&server->serviceMutex); + response->responseHeader.serviceResult = securityPolicy->channelModule. + newContext(securityPolicy, &userCertToken->certificateData, &tempChannelContext); + UA_LOCK(&server->serviceMutex); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(&server->config.logger, session, "ActivateSession: " + "Failed to create a context for the SecurityPolicy %.*s", + (int)securityPolicy->policyUri.length, + securityPolicy->policyUri.data); + goto securityRejected; + } + + /* Check the user token signature */ + response->responseHeader.serviceResult = + checkSignature(server, channel->securityPolicy, tempChannelContext, + &session->serverNonce, &request->userTokenSignature); + + /* Delete the temporary channel context */ + UA_UNLOCK(&server->serviceMutex); + securityPolicy->channelModule.deleteContext(tempChannelContext); + UA_LOCK(&server->serviceMutex); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "ActivateSession: User token signature check failed with StatusCode %s", + UA_StatusCode_name(response->responseHeader.serviceResult)); + goto securityRejected; + } + } +#endif + /* Callback into userland access control */ - response->responseHeader.serviceResult = - server->config.accessControl. + UA_UNLOCK(&server->serviceMutex); + response->responseHeader.serviceResult = server->config.accessControl. activateSession(server, &server->config.accessControl, ed, &channel->remoteCertificate, &session->sessionId, &request->userIdentityToken, &session->sessionHandle); + UA_LOCK(&server->serviceMutex); if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_LOG_WARNING_SESSION(&server->config.logger, session, "ActivateSession: The AccessControl " "plugin denied the activation with the StatusCode %s", UA_StatusCode_name(response->responseHeader.serviceResult)); - goto rejected; + goto securityRejected; } /* Attach the session to the currently used channel if the session isn't @@ -34729,29 +37477,65 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, goto rejected; } + /* Set the locale */ + response->responseHeader.serviceResult |= + UA_Array_copy(request->localeIds, request->localeIdsSize, + (void**)&tmpLocaleIds, &UA_TYPES[UA_TYPES_STRING]); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_Session_detachFromSecureChannel(session); + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "ActivateSession: Could not store the Session LocaleIds"); + goto rejected; + } + UA_Array_delete(session->localeIds, session->localeIdsSize, + &UA_TYPES[UA_TYPES_STRING]); + session->localeIds = tmpLocaleIds; + session->localeIdsSize = request->localeIdsSize; + UA_Session_updateLifetime(session); /* Activate the session */ if(!session->activated) { session->activated = true; - UA_atomic_addSize(&server->serverStats.ss.currentSessionCount, 1); - UA_atomic_addSize(&server->serverStats.ss.cumulatedSessionCount, 1); + server->activeSessionCount++; + server->serverDiagnosticsSummary.cumulatedSessionCount++; } +#ifdef UA_ENABLE_DIAGNOSTICS + saveClientUserId(&request->userIdentityToken, + &session->securityDiagnostics); + UA_String_clear(&session->securityDiagnostics.authenticationMechanism); + switch(utp->tokenType) { + case UA_USERTOKENTYPE_ANONYMOUS: + session->securityDiagnostics.authenticationMechanism = UA_STRING_ALLOC("Anonymous"); + break; + case UA_USERTOKENTYPE_USERNAME: + session->securityDiagnostics.authenticationMechanism = UA_STRING_ALLOC("UserName"); + break; + case UA_USERTOKENTYPE_CERTIFICATE: + session->securityDiagnostics.authenticationMechanism = UA_STRING_ALLOC("Certificate"); + break; + case UA_USERTOKENTYPE_ISSUEDTOKEN: + session->securityDiagnostics.authenticationMechanism = UA_STRING_ALLOC("IssuedToken"); + break; + default: break; + } +#endif + UA_LOG_INFO_SESSION(&server->config.logger, session, "ActivateSession: Session activated"); return; securityRejected: - UA_atomic_addSize(&server->serverStats.ss.securityRejectedSessionCount, 1); + server->serverDiagnosticsSummary.securityRejectedSessionCount++; rejected: - UA_atomic_addSize(&server->serverStats.ss.rejectedSessionCount, 1); + server->serverDiagnosticsSummary.rejectedSessionCount++; } void Service_CloseSession(UA_Server *server, UA_SecureChannel *channel, const UA_CloseSessionRequest *request, UA_CloseSessionResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Part 4, 5.6.4: When the CloseSession Service is called before the Session * is successfully activated, the Server shall reject the request if the @@ -34771,13 +37555,28 @@ Service_CloseSession(UA_Server *server, UA_SecureChannel *channel, return; } - UA_LOG_INFO_SESSION(&server->config.logger, session, "CloseSession"); + UA_assert(session); /* Assured by the previous section */ + UA_LOG_INFO_SESSION(&server->config.logger, session, "Closing the Session"); + +#ifdef UA_ENABLE_SUBSCRIPTIONS + /* If Subscriptions are not deleted, detach them from the Session */ + if(!request->deleteSubscriptions) { + UA_Subscription *sub, *sub_tmp; + TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, sub_tmp) { + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, sub, + "Detaching the Subscription from the Session"); + UA_Session_detachSubscription(server, session, sub, true); + } + } +#endif + + /* Remove the sesison */ response->responseHeader.serviceResult = UA_Server_removeSessionByToken(server, &session->header.authenticationToken, UA_DIAGNOSTICEVENT_CLOSE); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_attribute.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_attribute.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -34797,6 +37596,7 @@ Service_CloseSession(UA_Server *server, UA_SecureChannel *channel, * Copyright 2017 (c) Julian Grothoff * Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green) * Copyright 2017 (c) Henrik Norrman + * Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) */ @@ -34807,18 +37607,23 @@ Service_CloseSession(UA_Server *server, UA_SecureChannel *channel, /* Access Control */ /******************/ +/* Session for read operations can be NULL. For example for a MonitoredItem + * where the underlying Subscription was detached during CloseSession. */ + static UA_UInt32 getUserWriteMask(UA_Server *server, const UA_Session *session, - const UA_Node *node) { + const UA_NodeHead *head) { if(session == &server->adminSession) return 0xFFFFFFFF; /* the local admin user has all rights */ - UA_UInt32 retval = node->writeMask; - UA_UNLOCK(server->serviceMutex); - retval &= server->config.accessControl.getUserRightsMask(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, - &node->nodeId, node->context); - UA_LOCK(server->serviceMutex); - return retval; + UA_UInt32 mask = head->writeMask; + UA_UNLOCK(&server->serviceMutex); + mask &= server->config.accessControl. + getUserRightsMask(server, &server->config.accessControl, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &head->nodeId, head->context); + UA_LOCK(&server->serviceMutex); + return mask; } static UA_Byte @@ -34835,11 +37640,13 @@ getUserAccessLevel(UA_Server *server, const UA_Session *session, if(session == &server->adminSession) return 0xFF; /* the local admin user has all rights */ UA_Byte retval = node->accessLevel; - UA_UNLOCK(server->serviceMutex); - retval &= server->config.accessControl.getUserAccessLevel(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, - &node->nodeId, node->context); - UA_LOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); + retval &= server->config.accessControl. + getUserAccessLevel(server, &server->config.accessControl, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &node->head.nodeId, node->head.context); + UA_LOCK(&server->serviceMutex); return retval; } @@ -34848,13 +37655,16 @@ getUserExecutable(UA_Server *server, const UA_Session *session, const UA_MethodNode *node) { if(session == &server->adminSession) return true; /* the local admin user has all rights */ - UA_Boolean retval = node->executable; - UA_UNLOCK(server->serviceMutex); - retval &= server->config.accessControl.getUserExecutable(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, - &node->nodeId, node->context); - UA_LOCK(server->serviceMutex); - return retval; + UA_UNLOCK(&server->serviceMutex); + UA_Boolean userExecutable = node->executable; + userExecutable &= + server->config.accessControl. + getUserExecutable(server, &server->config.accessControl, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &node->head.nodeId, node->head.context); + UA_LOCK(&server->serviceMutex); + return userExecutable; } /****************/ @@ -34864,18 +37674,18 @@ getUserExecutable(UA_Server *server, const UA_Session *session, static UA_StatusCode readIsAbstractAttribute(const UA_Node *node, UA_Variant *v) { const UA_Boolean *isAbstract; - switch(node->nodeClass) { + switch(node->head.nodeClass) { case UA_NODECLASS_REFERENCETYPE: - isAbstract = &((const UA_ReferenceTypeNode*)node)->isAbstract; + isAbstract = &node->referenceTypeNode.isAbstract; break; case UA_NODECLASS_OBJECTTYPE: - isAbstract = &((const UA_ObjectTypeNode*)node)->isAbstract; + isAbstract = &node->objectTypeNode.isAbstract; break; case UA_NODECLASS_VARIABLETYPE: - isAbstract = &((const UA_VariableTypeNode*)node)->isAbstract; + isAbstract = &node->variableTypeNode.isAbstract; break; case UA_NODECLASS_DATATYPE: - isAbstract = &((const UA_DataTypeNode*)node)->isAbstract; + isAbstract = &node->dataTypeNode.isAbstract; break; default: return UA_STATUSCODE_BADATTRIBUTEIDINVALID; @@ -34890,12 +37700,14 @@ readValueAttributeFromNode(UA_Server *server, UA_Session *session, UA_NumericRange *rangeptr) { /* Update the value by the user callback */ if(vn->value.data.callback.onRead) { - UA_UNLOCK(server->serviceMutex); - vn->value.data.callback.onRead(server, &session->sessionId, - session->sessionHandle, &vn->nodeId, - vn->context, rangeptr, &vn->value.data.value); - UA_LOCK(server->serviceMutex); - vn = (const UA_VariableNode*)UA_NODESTORE_GET(server, &vn->nodeId); + UA_UNLOCK(&server->serviceMutex); + vn->value.data.callback.onRead(server, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &vn->head.nodeId, vn->head.context, rangeptr, + &vn->value.data.value); + UA_LOCK(&server->serviceMutex); + vn = (const UA_VariableNode*)UA_NODESTORE_GET(server, &vn->head.nodeId); if(!vn) return UA_STATUSCODE_BADNODEIDUNKNOWN; } @@ -34922,11 +37734,14 @@ readValueAttributeFromDataSource(UA_Server *server, UA_Session *session, timestamps == UA_TIMESTAMPSTORETURN_BOTH); UA_DataValue v2; UA_DataValue_init(&v2); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); UA_StatusCode retval = vn->value.dataSource. - read(server, &session->sessionId, session->sessionHandle, - &vn->nodeId, vn->context, sourceTimeStamp, rangeptr, &v2); - UA_LOCK(server->serviceMutex); + read(server, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &vn->head.nodeId, vn->head.context, + sourceTimeStamp, rangeptr, &v2); + UA_LOCK(&server->serviceMutex); if(v2.hasValue && v2.value.storageType == UA_VARIANT_DATA_NODELETE) { retval = UA_DataValue_copy(&v2, v); UA_DataValue_clear(&v2); @@ -34951,11 +37766,58 @@ readValueAttributeComplete(UA_Server *server, UA_Session *session, rangeptr = ⦥ } - /* Read the value */ - if(vn->valueSource == UA_VALUESOURCE_DATA) - retval = readValueAttributeFromNode(server, session, vn, v, rangeptr); - else - retval = readValueAttributeFromDataSource(server, session, vn, v, timestamps, rangeptr); + switch(vn->valueBackend.backendType) { + case UA_VALUEBACKENDTYPE_INTERNAL: + retval = readValueAttributeFromNode(server, session, vn, v, rangeptr); + //TODO change old structure to value backend + break; + case UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK: + retval = readValueAttributeFromDataSource(server, session, vn, v, + timestamps, rangeptr); + //TODO change old structure to value backend + break; + case UA_VALUEBACKENDTYPE_EXTERNAL: + if(vn->valueBackend.backend.external.callback.notificationRead){ + retval = vn->valueBackend.backend.external.callback. + notificationRead(server, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &vn->head.nodeId, vn->head.context, rangeptr); + } else { + retval = UA_STATUSCODE_BADNOTREADABLE; + } + if(retval != UA_STATUSCODE_GOOD){ + break; + } + /* Set the result */ + if(rangeptr) + retval = UA_DataValue_copyVariantRange( + *vn->valueBackend.backend.external.value, v, *rangeptr); + else + retval = UA_DataValue_copy(*vn->valueBackend.backend.external.value, v); + break; + case UA_VALUEBACKENDTYPE_NONE: + /* Read the value */ + if(vn->valueSource == UA_VALUESOURCE_DATA) + retval = readValueAttributeFromNode(server, session, vn, v, rangeptr); + else + retval = readValueAttributeFromDataSource(server, session, vn, v, + timestamps, rangeptr); + /* end lagacy */ + break; + } + + /* Static Variables and VariableTypes have timestamps of "now". Will be set + * below in the absence of predefined timestamps. */ + if(vn->head.nodeClass == UA_NODECLASS_VARIABLE) { + if(!vn->isDynamic) { + v->hasServerTimestamp = false; + v->hasSourceTimestamp = false; + } + } else { + v->hasServerTimestamp = false; + v->hasSourceTimestamp = false; + } /* Clean up */ if(rangeptr) @@ -34966,7 +37828,8 @@ readValueAttributeComplete(UA_Server *server, UA_Session *session, UA_StatusCode readValueAttribute(UA_Server *server, UA_Session *session, const UA_VariableNode *vn, UA_DataValue *v) { - return readValueAttributeComplete(server, session, vn, UA_TIMESTAMPSTORETURN_NEITHER, NULL, v); + return readValueAttributeComplete(server, session, vn, + UA_TIMESTAMPSTORETURN_NEITHER, NULL, v); } static const UA_String binEncoding = {sizeof("Default Binary")-1, (UA_Byte*)"Default Binary"}; @@ -34974,7 +37837,7 @@ static const UA_String xmlEncoding = {sizeof("Default XML")-1, (UA_Byte*)"Defaul static const UA_String jsonEncoding = {sizeof("Default JSON")-1, (UA_Byte*)"Default JSON"}; #define CHECK_NODECLASS(CLASS) \ - if(!(node->nodeClass & (CLASS))) { \ + if(!(node->head.nodeClass & (CLASS))) { \ retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; \ break; \ } @@ -34983,7 +37846,7 @@ static const UA_String jsonEncoding = {sizeof("Default JSON")-1, (UA_Byte*)"Defa static const UA_DataType * findDataType(const UA_Node *node, const UA_DataTypeArray *customTypes) { for(size_t i = 0; i < UA_TYPES_COUNT; ++i) { - if(UA_NodeId_equal(&UA_TYPES[i].typeId, &node->nodeId)) { + if(UA_NodeId_equal(&UA_TYPES[i].typeId, &node->head.nodeId)) { return &UA_TYPES[i]; } } @@ -34991,7 +37854,7 @@ findDataType(const UA_Node *node, const UA_DataTypeArray *customTypes) { // lookup custom type while(customTypes) { for(size_t i = 0; i < customTypes->typesSize; ++i) { - if(UA_NodeId_equal(&customTypes->types[i].typeId, &node->nodeId)) + if(UA_NodeId_equal(&customTypes->types[i].typeId, &node->head.nodeId)) return &customTypes->types[i]; } customTypes = customTypes->next; @@ -35001,8 +37864,10 @@ findDataType(const UA_Node *node, const UA_DataTypeArray *customTypes) { static UA_StatusCode getStructureDefinition(const UA_DataType *type, UA_StructureDefinition *def) { - def->defaultEncodingId = - UA_NODEID_NUMERIC(type->typeId.namespaceIndex, type->binaryEncodingId); + UA_StatusCode retval = + UA_NodeId_copy(&type->binaryEncodingId, &def->defaultEncodingId); + if(retval != UA_STATUSCODE_GOOD) + return retval; switch(type->typeKind) { case UA_DATATYPEKIND_STRUCTURE: def->structureType = UA_STRUCTURETYPE_STRUCTURE; @@ -35020,22 +37885,22 @@ getStructureDefinition(const UA_DataType *type, UA_StructureDefinition *def) { return UA_STATUSCODE_BADENCODINGERROR; } def->fieldsSize = type->membersSize; - def->fields = - (UA_StructureField *)UA_calloc(def->fieldsSize, sizeof(UA_StructureField)); + def->fields = (UA_StructureField *) + UA_calloc(def->fieldsSize, sizeof(UA_StructureField)); if(!def->fields) { + UA_NodeId_clear(&def->defaultEncodingId); return UA_STATUSCODE_BADOUTOFMEMORY; } - const UA_DataType *typelists[2] = {UA_TYPES, &type[-type->typeIndex]}; + for(size_t cnt = 0; cnt < def->fieldsSize; cnt++) { const UA_DataTypeMember *m = &type->members[cnt]; def->fields[cnt].valueRank = UA_TRUE == m->isArray ? 1 : -1; def->fields[cnt].arrayDimensions = NULL; def->fields[cnt].arrayDimensionsSize = 0; - def->fields[cnt].name = - UA_STRING((char *)(uintptr_t)m->memberName); + def->fields[cnt].name = UA_STRING((char *)(uintptr_t)m->memberName); def->fields[cnt].description.locale = UA_STRING_NULL; def->fields[cnt].description.text = UA_STRING_NULL; - def->fields[cnt].dataType = typelists[!m->namespaceZero][m->memberTypeIndex].typeId; + def->fields[cnt].dataType = m->memberType->typeId; def->fields[cnt].maxStringLength = 0; def->fields[cnt].isOptional = m->isOptional; } @@ -35050,8 +37915,11 @@ void ReadWithNode(const UA_Node *node, UA_Server *server, UA_Session *session, UA_TimestampsToReturn timestampsToReturn, const UA_ReadValueId *id, UA_DataValue *v) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, - "Read the attribute %" PRIi32, id->attributeId); + UA_LOG_NODEID_DEBUG(&node->head.nodeId, + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Read attribute %"PRIi32 " of Node %.*s", + id->attributeId, (int)nodeIdStr.length, + nodeIdStr.data)); /* Only Binary Encoding is supported */ if(id->dataEncoding.name.length > 0 && @@ -35076,129 +37944,140 @@ ReadWithNode(const UA_Node *node, UA_Server *server, UA_Session *session, UA_StatusCode retval = UA_STATUSCODE_GOOD; switch(id->attributeId) { case UA_ATTRIBUTEID_NODEID: - retval = UA_Variant_setScalarCopy(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]); + retval = UA_Variant_setScalarCopy(&v->value, &node->head.nodeId, + &UA_TYPES[UA_TYPES_NODEID]); break; case UA_ATTRIBUTEID_NODECLASS: - retval = UA_Variant_setScalarCopy(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); + retval = UA_Variant_setScalarCopy(&v->value, &node->head.nodeClass, + &UA_TYPES[UA_TYPES_NODECLASS]); break; case UA_ATTRIBUTEID_BROWSENAME: - retval = UA_Variant_setScalarCopy(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + retval = UA_Variant_setScalarCopy(&v->value, &node->head.browseName, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); break; case UA_ATTRIBUTEID_DISPLAYNAME: - retval = UA_Variant_setScalarCopy(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Variant_setScalarCopy(&v->value, &node->head.displayName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); break; case UA_ATTRIBUTEID_DESCRIPTION: - retval = UA_Variant_setScalarCopy(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Variant_setScalarCopy(&v->value, &node->head.description, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); break; case UA_ATTRIBUTEID_WRITEMASK: - retval = UA_Variant_setScalarCopy(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]); + retval = UA_Variant_setScalarCopy(&v->value, &node->head.writeMask, + &UA_TYPES[UA_TYPES_UINT32]); break; case UA_ATTRIBUTEID_USERWRITEMASK: { - UA_UInt32 userWriteMask = getUserWriteMask(server, session, node); - retval = UA_Variant_setScalarCopy(&v->value, &userWriteMask, &UA_TYPES[UA_TYPES_UINT32]); + UA_UInt32 userWriteMask = getUserWriteMask(server, session, &node->head); + retval = UA_Variant_setScalarCopy(&v->value, &userWriteMask, + &UA_TYPES[UA_TYPES_UINT32]); break; } case UA_ATTRIBUTEID_ISABSTRACT: retval = readIsAbstractAttribute(node, &v->value); break; case UA_ATTRIBUTEID_SYMMETRIC: CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric, - &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Variant_setScalarCopy(&v->value, &node->referenceTypeNode.symmetric, + &UA_TYPES[UA_TYPES_BOOLEAN]); break; case UA_ATTRIBUTEID_INVERSENAME: CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName, - &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + retval = UA_Variant_setScalarCopy(&v->value, &node->referenceTypeNode.inverseName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); break; case UA_ATTRIBUTEID_CONTAINSNOLOOPS: CHECK_NODECLASS(UA_NODECLASS_VIEW); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->containsNoLoops, - &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Variant_setScalarCopy(&v->value, &node->viewNode.containsNoLoops, + &UA_TYPES[UA_TYPES_BOOLEAN]); break; case UA_ATTRIBUTEID_EVENTNOTIFIER: CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); - if(node->nodeClass == UA_NODECLASS_VIEW) { - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->eventNotifier, - &UA_TYPES[UA_TYPES_BYTE]); - } - else{ - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ObjectNode*)node)->eventNotifier, - &UA_TYPES[UA_TYPES_BYTE]); + if(node->head.nodeClass == UA_NODECLASS_VIEW) { + retval = UA_Variant_setScalarCopy(&v->value, &node->viewNode.eventNotifier, + &UA_TYPES[UA_TYPES_BYTE]); + } else { + retval = UA_Variant_setScalarCopy(&v->value, &node->objectNode.eventNotifier, + &UA_TYPES[UA_TYPES_BYTE]); } break; case UA_ATTRIBUTEID_VALUE: { CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); - /* VariableTypes don't have the AccessLevel concept. Always allow reading the value. */ - if(node->nodeClass == UA_NODECLASS_VARIABLE) { + /* VariableTypes don't have the AccessLevel concept. Always allow + * reading the value. */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE) { /* The access to a value variable is granted via the AccessLevel * and UserAccessLevel attributes */ - UA_Byte accessLevel = getAccessLevel(server, session, (const UA_VariableNode*)node); + UA_Byte accessLevel = getAccessLevel(server, session, &node->variableNode); if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) { retval = UA_STATUSCODE_BADNOTREADABLE; break; } - accessLevel = getUserAccessLevel(server, session, - (const UA_VariableNode*)node); + accessLevel = getUserAccessLevel(server, session, &node->variableNode); if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) { retval = UA_STATUSCODE_BADUSERACCESSDENIED; break; } } - retval = readValueAttributeComplete(server, session, (const UA_VariableNode*)node, + retval = readValueAttributeComplete(server, session, &node->variableNode, timestampsToReturn, &id->indexRange, v); break; } case UA_ATTRIBUTEID_DATATYPE: CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode*)node)->dataType, + retval = UA_Variant_setScalarCopy(&v->value, &node->variableTypeNode.dataType, &UA_TYPES[UA_TYPES_NODEID]); break; case UA_ATTRIBUTEID_VALUERANK: CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode*)node)->valueRank, + retval = UA_Variant_setScalarCopy(&v->value, &node->variableTypeNode.valueRank, &UA_TYPES[UA_TYPES_INT32]); break; case UA_ATTRIBUTEID_ARRAYDIMENSIONS: CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); - retval = UA_Variant_setArrayCopy(&v->value, ((const UA_VariableTypeNode*)node)->arrayDimensions, - ((const UA_VariableTypeNode*)node)->arrayDimensionsSize, + retval = UA_Variant_setArrayCopy(&v->value, node->variableTypeNode.arrayDimensions, + node->variableTypeNode.arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); break; case UA_ATTRIBUTEID_ACCESSLEVEL: CHECK_NODECLASS(UA_NODECLASS_VARIABLE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->accessLevel, + retval = UA_Variant_setScalarCopy(&v->value, &node->variableNode.accessLevel, &UA_TYPES[UA_TYPES_BYTE]); break; case UA_ATTRIBUTEID_USERACCESSLEVEL: { CHECK_NODECLASS(UA_NODECLASS_VARIABLE); - UA_Byte userAccessLevel = getUserAccessLevel(server, session, (const UA_VariableNode*)node); - retval = UA_Variant_setScalarCopy(&v->value, &userAccessLevel, &UA_TYPES[UA_TYPES_BYTE]); + UA_Byte userAccessLevel = getUserAccessLevel(server, session, &node->variableNode); + retval = UA_Variant_setScalarCopy(&v->value, &userAccessLevel, + &UA_TYPES[UA_TYPES_BYTE]); break; } case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL: CHECK_NODECLASS(UA_NODECLASS_VARIABLE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval, - &UA_TYPES[UA_TYPES_DOUBLE]); + retval = UA_Variant_setScalarCopy(&v->value, + &node->variableNode.minimumSamplingInterval, + &UA_TYPES[UA_TYPES_DOUBLE]); break; case UA_ATTRIBUTEID_HISTORIZING: CHECK_NODECLASS(UA_NODECLASS_VARIABLE); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->historizing, - &UA_TYPES[UA_TYPES_BOOLEAN]); + retval = UA_Variant_setScalarCopy(&v->value, &node->variableNode.historizing, + &UA_TYPES[UA_TYPES_BOOLEAN]); break; case UA_ATTRIBUTEID_EXECUTABLE: CHECK_NODECLASS(UA_NODECLASS_METHOD); - retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->executable, + retval = UA_Variant_setScalarCopy(&v->value, &node->methodNode.executable, &UA_TYPES[UA_TYPES_BOOLEAN]); break; case UA_ATTRIBUTEID_USEREXECUTABLE: { CHECK_NODECLASS(UA_NODECLASS_METHOD); - UA_Boolean userExecutable = getUserExecutable(server, session, (const UA_MethodNode*)node); - retval = UA_Variant_setScalarCopy(&v->value, &userExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); + UA_Boolean userExecutable = + getUserExecutable(server, session, &node->methodNode); + retval = UA_Variant_setScalarCopy(&v->value, &userExecutable, + &UA_TYPES[UA_TYPES_BOOLEAN]); break; } case UA_ATTRIBUTEID_DATATYPEDEFINITION: { CHECK_NODECLASS(UA_NODECLASS_DATATYPE); #ifdef UA_ENABLE_TYPEDESCRIPTION - const UA_DataType *type = findDataType(node, server->config.customDataTypes); + const UA_DataType *type = + findDataType(node, server->config.customDataTypes); if(!type) { retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; break; @@ -35223,19 +38102,18 @@ ReadWithNode(const UA_Node *node, UA_Server *server, UA_Session *session, retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; } - /* Return error code when reading has failed */ if(retval != UA_STATUSCODE_GOOD) { + /* Reading has failed but can not return because we may need to add timestamp */ v->hasStatus = true; v->status = retval; - return; + } else { + v->hasValue = true; } - v->hasValue = true; - /* Create server timestamp */ if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER || timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH) { - if (!v->hasServerTimestamp) { + if(!v->hasServerTimestamp) { v->serverTimestamp = UA_DateTime_now(); v->hasServerTimestamp = true; } @@ -35277,7 +38155,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request, UA_ReadResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing ReadRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Check if the timestampstoreturn is valid */ if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) { @@ -35298,19 +38176,23 @@ Service_Read(UA_Server *server, UA_Session *session, return; } - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_Read, - request, - &request->nodesToReadSize, &UA_TYPES[UA_TYPES_READVALUEID], - &response->resultsSize, &UA_TYPES[UA_TYPES_DATAVALUE]); + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_Read, + request, &request->nodesToReadSize, + &UA_TYPES[UA_TYPES_READVALUEID], + &response->resultsSize, + &UA_TYPES[UA_TYPES_DATAVALUE]); } UA_DataValue UA_Server_readWithSession(UA_Server *server, UA_Session *session, const UA_ReadValueId *item, UA_TimestampsToReturn timestampsToReturn) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + UA_DataValue dv; UA_DataValue_init(&dv); @@ -35333,14 +38215,14 @@ UA_Server_readWithSession(UA_Server *server, UA_Session *session, UA_DataValue readAttribute(UA_Server *server, const UA_ReadValueId *item, UA_TimestampsToReturn timestamps) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); return UA_Server_readWithSession(server, &server->adminSession, item, timestamps); } UA_StatusCode readWithReadValue(UA_Server *server, const UA_NodeId *nodeId, - const UA_AttributeId attributeId, void *v) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + const UA_AttributeId attributeId, void *v) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Call the read service */ UA_ReadValueId item; @@ -35376,9 +38258,9 @@ readWithReadValue(UA_Server *server, const UA_NodeId *nodeId, UA_DataValue UA_Server_read(UA_Server *server, const UA_ReadValueId *item, UA_TimestampsToReturn timestamps) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_DataValue dv = readAttribute(server, item, timestamps); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return dv; } @@ -35387,9 +38269,9 @@ UA_Server_read(UA_Server *server, const UA_ReadValueId *item, UA_StatusCode __UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, const UA_AttributeId attributeId, void *v) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = readWithReadValue(server, nodeId, attributeId, v); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -35397,7 +38279,9 @@ UA_StatusCode readObjectProperty(UA_Server *server, const UA_NodeId objectId, const UA_QualifiedName propertyName, UA_Variant *value) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + /* Create a BrowsePath to get the target NodeId */ UA_RelativePathElement rpe; UA_RelativePathElement_init(&rpe); rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); @@ -35419,7 +38303,9 @@ readObjectProperty(UA_Server *server, const UA_NodeId objectId, return retval; } - retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, value); + /* Use the first result from the BrowsePath */ + retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId, + UA_ATTRIBUTEID_VALUE, value); UA_BrowsePathResult_clear(&bpr); return retval; @@ -35430,9 +38316,9 @@ UA_StatusCode UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId, const UA_QualifiedName propertyName, UA_Variant *value) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = readObjectProperty(server, objectId, propertyName, value); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -35451,47 +38337,48 @@ typeEquivalence(const UA_DataType *t) { static const UA_NodeId enumNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ENUMERATION}}; UA_Boolean -compatibleDataType(UA_Server *server, const UA_NodeId *dataType, - const UA_NodeId *constraintDataType, UA_Boolean isValue) { +compatibleValueDataType(UA_Server *server, const UA_DataType *dataType, + const UA_NodeId *constraintDataType) { + if(compatibleDataTypes(server, &dataType->typeId, constraintDataType)) + return true; + + /* For actual values, the constraint DataType may be a subtype of the + * DataType of the value. E.g. UtcTime is subtype of DateTime. But it still + * is a DateTime value when transferred over the wire. */ + if(isNodeInTree_singleRef(server, constraintDataType, &dataType->typeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) + return true; + + return false; +} + +UA_Boolean +compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType, + const UA_NodeId *constraintDataType) { /* Do not allow empty datatypes */ if(UA_NodeId_isNull(dataType)) return false; - /* No constraint (TODO: use variant instead) */ - if(UA_NodeId_isNull(constraintDataType)) + /* No constraint or Variant / BaseDataType which allows any content */ + if(UA_NodeId_isNull(constraintDataType) || + UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId)) return true; /* Same datatypes */ - if (UA_NodeId_equal(dataType, constraintDataType)) - return true; - - /* Variant allows any subtype */ - if(UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId)) + if(UA_NodeId_equal(dataType, constraintDataType)) return true; - /* Is the value-type a subtype of the required type? */ - if(isNodeInTree(server, dataType, constraintDataType, &subtypeId, 1)) + /* Is the DataType a subtype of the constraint type? */ + if(isNodeInTree_singleRef(server, dataType, constraintDataType, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) return true; - /* Enum allows Int32 (only) */ + /* The constraint is an enum -> allow writing Int32 */ if(UA_NodeId_equal(dataType, &UA_TYPES[UA_TYPES_INT32].typeId) && - isNodeInTree(server, constraintDataType, &enumNodeId, &subtypeId, 1)) + isNodeInTree_singleRef(server, constraintDataType, &enumNodeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) return true; - /* More checks for the data type of real values (variants) */ - if(isValue) { - /* If value is a built-in type: The target data type may be a sub type of - * the built-in type. (e.g. UtcTime is sub-type of DateTime and has a - * DateTime value). A type is builtin if its NodeId is in Namespace 0 and - * has a numeric identifier <= 25 (DiagnosticInfo) */ - if(dataType->namespaceIndex == 0 && - dataType->identifierType == UA_NODEIDTYPE_NUMERIC && - dataType->identifier.numeric <= 25 && - isNodeInTree(server, constraintDataType, - dataType, &subtypeId, 1)) - return true; - } - return false; } @@ -35510,10 +38397,13 @@ compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session, return false; } - /* case -3, UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: the value can be a scalar or a one dimensional array */ - /* case -2, UA_VALUERANK_ANY: the value can be a scalar or an array with any number of dimensions */ - /* case -1, UA_VALUERANK_SCALAR: the value is a scalar */ - /* case 0, UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: the value is an array with one or more dimensions */ + /* case -3, UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: the value can be a scalar + * or a one dimensional array + * case -2, UA_VALUERANK_ANY: the value can be a scalar or an array with any + * number of dimensions + * case -1, UA_VALUERANK_SCALAR: the value is a scalar + * case 0, UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: the value is an array with + * one or more dimensions */ if(valueRank <= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS) { if(arrayDimensionsSize > 0) { UA_LOG_INFO_SESSION(&server->config.logger, session, @@ -35523,10 +38413,12 @@ compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session, return true; } - /* case >= 1, UA_VALUERANK_ONE_DIMENSION: the value is an array with the specified number of dimensions */ + /* case >= 1, UA_VALUERANK_ONE_DIMENSION: the value is an array with the + specified number of dimensions */ if(arrayDimensionsSize != (size_t)valueRank) { UA_LOG_INFO_SESSION(&server->config.logger, session, - "The number of ArrayDimensions is not equal to the (positive) ValueRank"); + "The number of ArrayDimensions is not equal to " + "the (positive) ValueRank"); return false; } return true; @@ -35536,21 +38428,25 @@ UA_Boolean compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank) { /* Check if the valuerank of the variabletype allows the change. */ switch(constraintValueRank) { - case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* the value can be a scalar or a one dimensional array */ + case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* the value can be a scalar or a + one dimensional array */ if(valueRank != UA_VALUERANK_SCALAR && valueRank != UA_VALUERANK_ONE_DIMENSION) return false; break; - case UA_VALUERANK_ANY: /* the value can be a scalar or an array with any number of dimensions */ + case UA_VALUERANK_ANY: /* the value can be a scalar or an array with any + number of dimensions */ break; case UA_VALUERANK_SCALAR: /* the value is a scalar */ if(valueRank != UA_VALUERANK_SCALAR) return false; break; - case UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: /* the value is an array with one or more dimensions */ + case UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: /* the value is an array with one + or more dimensions */ if(valueRank < (UA_Int32) UA_VALUERANK_ONE_OR_MORE_DIMENSIONS) return false; break; - default: /* >= 1: the value is an array with the specified number of dimensions */ + default: /* >= 1: the value is an array with the specified number of + dimensions */ if(valueRank != constraintValueRank) return false; break; @@ -35578,9 +38474,11 @@ compatibleValueRankValue(UA_Int32 valueRank, const UA_Variant *value) { /* We cannot simply use compatibleValueRankArrayDimensions since we can have * defined ArrayDimensions for the value if the ValueRank is -2 */ switch(valueRank) { - case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* The value can be a scalar or a one dimensional array */ + case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* The value can be a scalar or a + one dimensional array */ return (arrayDims <= 1); - case UA_VALUERANK_ANY: /* The value can be a scalar or an array with any number of dimensions */ + case UA_VALUERANK_ANY: /* The value can be a scalar or an array with any + number of dimensions */ return true; case UA_VALUERANK_SCALAR: /* The value is a scalar */ return (arrayDims == 0); @@ -35635,11 +38533,16 @@ compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimens valueArrayDimensionsSize, valueArrayDimensions); } +const char *reason_EmptyType = "Empty value only allowed for BaseDataType"; +const char *reason_ValueDataType = "DataType of the value is incompatible"; +const char *reason_ValueArrayDimensions = "ArrayDimensions of the value are incompatible"; +const char *reason_ValueValueRank = "ValueRank of the value is incompatible"; + UA_Boolean compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId, UA_Int32 targetValueRank, size_t targetArrayDimensionsSize, const UA_UInt32 *targetArrayDimensions, const UA_Variant *value, - const UA_NumericRange *range) { + const UA_NumericRange *range, const char **reason) { /* Empty value */ if(!value->type) { /* Empty value is allowed for BaseDataType */ @@ -35647,45 +38550,61 @@ compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetD UA_NodeId_equal(targetDataTypeId, &UA_NODEID_NULL)) return true; - /* Allow empty node values since existing information models may have - * variables with no value, e.g. OldValues - ns=0;i=3024. See also - * #1889, https://github.com/open62541/open62541/pull/1889#issuecomment-403506538 */ - if(server->config.relaxEmptyValueConstraint) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, - "Only Variables with data type BaseDataType can contain an " - "empty value. Allow via explicit constraint relaxation."); + /* Ignore if that is configured */ + if(server->bootstrapNS0 || + server->config.allowEmptyVariables == UA_RULEHANDLING_ACCEPT) return true; - } UA_LOG_INFO_SESSION(&server->config.logger, session, - "Only Variables with data type BaseDataType can contain an empty value"); + "Only Variables with data type BaseDataType " + "can contain an empty value"); + + /* Ignore if that is configured */ + if(server->config.allowEmptyVariables == UA_RULEHANDLING_WARN) + return true; + + /* Default handling is to abort */ + *reason = reason_EmptyType; return false; } - /* Has the value a subtype of the required type? BaseDataType (Variant) can - * be anything... */ - if(!compatibleDataType(server, &value->type->typeId, targetDataTypeId, true)) + /* Is the datatype compatible? */ + if(!compatibleValueDataType(server, value->type, targetDataTypeId)) { + *reason = reason_ValueDataType; return false; + } /* Array dimensions are checked later when writing the range */ if(range) return true; /* See if the array dimensions match. */ - if(!compatibleValueArrayDimensions(value, targetArrayDimensionsSize, targetArrayDimensions)) + if(!compatibleValueArrayDimensions(value, targetArrayDimensionsSize, + targetArrayDimensions)) { + *reason = reason_ValueArrayDimensions; return false; + } /* Check if the valuerank allows for the value dimension */ - return compatibleValueRankValue(targetValueRank, value); + if(!compatibleValueRankValue(targetValueRank, value)) { + *reason = reason_ValueValueRank; + return false; + } + + return true; } /*****************/ /* Write Service */ /*****************/ -static void -adjustValue(UA_Server *server, UA_Variant *value, - const UA_NodeId *targetDataTypeId) { +void +adjustValueType(UA_Server *server, UA_Variant *value, + const UA_NodeId *targetDataTypeId) { + /* If the value is empty, there is nothing we can do here */ + if(!value->type) + return; + const UA_DataType *targetDataType = UA_findDataType(targetDataTypeId); if(!targetDataType) return; @@ -35703,7 +38622,7 @@ adjustValue(UA_Server *server, UA_Variant *value, } /* An enum was sent as an int32, or an opaque type as a bytestring. This - * is detected with the typeIndex indicating the "true" datatype. */ + * is detected with the typeKind indicating the "true" datatype. */ UA_DataTypeKind te1 = typeEquivalence(targetDataType); UA_DataTypeKind te2 = typeEquivalence(value->type); if(te1 == te2 && te1 <= UA_DATATYPEKIND_ENUM) { @@ -35723,15 +38642,16 @@ writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session, /* If this is a variabletype, there must be no instances or subtypes of it * when we do the change */ - if(node->nodeClass == UA_NODECLASS_VARIABLETYPE && - UA_Node_hasSubTypeOrInstances((UA_Node*)node)) { + if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE && + UA_Node_hasSubTypeOrInstances(&node->head)) { UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, "Cannot change a variable type with existing instances"); return UA_STATUSCODE_BADINTERNALERROR; } /* Check that the array dimensions match with the valuerank */ - if(!compatibleValueRankArrayDimensions(server, session, node->valueRank, arrayDimensionsSize)) { + if(!compatibleValueRankArrayDimensions(server, session, node->valueRank, + arrayDimensionsSize)) { UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, "Cannot write the ArrayDimensions. The ValueRank does not match."); return UA_STATUSCODE_BADTYPEMISMATCH; @@ -35754,7 +38674,8 @@ writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session, if(retval != UA_STATUSCODE_GOOD) return retval; if(value.hasValue) { - if(!compatibleValueArrayDimensions(&value.value, arrayDimensionsSize, arrayDimensions)) + if(!compatibleValueArrayDimensions(&value.value, arrayDimensionsSize, + arrayDimensions)) retval = UA_STATUSCODE_BADTYPEMISMATCH; UA_DataValue_clear(&value); if(retval != UA_STATUSCODE_GOOD) { @@ -35789,8 +38710,8 @@ writeValueRankAttribute(UA_Server *server, UA_Session *session, /* If this is a variabletype, there must be no instances or subtypes of it * when we do the change */ - if(node->nodeClass == UA_NODECLASS_VARIABLETYPE && - UA_Node_hasSubTypeOrInstances((const UA_Node*)node)) + if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE && + UA_Node_hasSubTypeOrInstances(&node->head)) return UA_STATUSCODE_BADINTERNALERROR; /* Check if the valuerank of the variabletype allows the change. */ @@ -35834,12 +38755,12 @@ writeDataTypeAttribute(UA_Server *server, UA_Session *session, /* If this is a variabletype, there must be no instances or subtypes of it when we do the change */ - if(node->nodeClass == UA_NODECLASS_VARIABLETYPE && - UA_Node_hasSubTypeOrInstances((const UA_Node*)node)) + if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE && + UA_Node_hasSubTypeOrInstances(&node->head)) return UA_STATUSCODE_BADINTERNALERROR; /* Does the new type match the constraints of the variabletype? */ - if(!compatibleDataType(server, dataType, &type->dataType, false)) + if(!compatibleDataTypes(server, dataType, &type->dataType)) return UA_STATUSCODE_BADTYPEMISMATCH; /* Check if the current value would match the new type */ @@ -35849,9 +38770,10 @@ writeDataTypeAttribute(UA_Server *server, UA_Session *session, if(retval != UA_STATUSCODE_GOOD) return retval; if(value.hasValue) { + const char *reason; /* temp value */ if(!compatibleValue(server, session, dataType, node->valueRank, node->arrayDimensionsSize, node->arrayDimensions, - &value.value, NULL)) + &value.value, NULL, &reason)) retval = UA_STATUSCODE_BADTYPEMISMATCH; UA_DataValue_clear(&value); if(retval != UA_STATUSCODE_GOOD) { @@ -35925,13 +38847,15 @@ writeValueAttributeWithRange(UA_VariableNode *node, const UA_DataValue *value, /* Stack layout: ... | node */ static UA_StatusCode -writeValueAttribute(UA_Server *server, UA_Session *session, - UA_VariableNode *node, const UA_DataValue *value, - const UA_String *indexRange) { +writeNodeValueAttribute(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_DataValue *value, + const UA_String *indexRange) { UA_assert(node != NULL); + UA_assert(session != NULL); /* Parse the range */ UA_NumericRange range; + range.dimensions = NULL; UA_NumericRange *rangeptr = NULL; UA_StatusCode retval = UA_STATUSCODE_GOOD; if(indexRange && indexRange->length > 0) { @@ -35947,7 +38871,7 @@ writeValueAttribute(UA_Server *server, UA_Session *session, /* Type checking. May change the type of editableValue */ if(value->hasValue && value->value.type) { - adjustValue(server, &adjustedValue.value, &node->dataType); + adjustValueType(server, &adjustedValue.value, &node->dataType); /* The value may be an extension object, especially the nodeset compiler * uses extension objects to write variable values. If value is an @@ -35959,88 +38883,125 @@ writeValueAttribute(UA_Server *server, UA_Session *session, value->value.type->typeId.identifier.numeric == UA_NS0ID_STRUCTURE) nodeDataTypePtr = &nodeDataType; + const char *reason; if(!compatibleValue(server, session, nodeDataTypePtr, node->valueRank, node->arrayDimensionsSize, node->arrayDimensions, - &adjustedValue.value, rangeptr)) { - if(rangeptr) - UA_free(range.dimensions); + &adjustedValue.value, rangeptr, &reason)) { + UA_LOG_NODEID_WARNING(&node->head.nodeId, + if(session == &server->adminSession) { + /* If the value is written via the local API, log a warning */ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Writing the value of Node %.*s failed with the " + "following reason: %s", + (int)nodeIdStr.length, nodeIdStr.data, reason); + } else { + /* Don't spam the logs if writing from remote failed */ + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Writing the value of Node %.*s failed with the " + "following reason: %s", + (int)nodeIdStr.length, nodeIdStr.data, reason); + }); + if(rangeptr && rangeptr->dimensions != NULL) + UA_free(rangeptr->dimensions); return UA_STATUSCODE_BADTYPEMISMATCH; } } - /* Ok, do it */ - if(node->valueSource == UA_VALUESOURCE_DATA) { - /* Set the source timestamp if there is none */ - UA_DateTime now = UA_DateTime_now(); - if(!adjustedValue.hasSourceTimestamp) { - adjustedValue.sourceTimestamp = now; - adjustedValue.hasSourceTimestamp = true; - } + /* Set the source timestamp if there is none */ + UA_DateTime now = UA_DateTime_now(); + if(!adjustedValue.hasSourceTimestamp) { + adjustedValue.sourceTimestamp = now; + adjustedValue.hasSourceTimestamp = true; + } - if(!adjustedValue.hasServerTimestamp) { - adjustedValue.serverTimestamp = now; - adjustedValue.hasServerTimestamp = true; - } + /* Update the timestamp when the value was last updated in the server */ + adjustedValue.serverTimestamp = now; + adjustedValue.hasServerTimestamp = true; - if(!rangeptr) - retval = writeValueAttributeWithoutRange(node, &adjustedValue); - else - retval = writeValueAttributeWithRange(node, &adjustedValue, rangeptr); + switch(node->valueBackend.backendType) { + case UA_VALUEBACKENDTYPE_NONE: + /* Ok, do it */ + if(node->valueSource == UA_VALUESOURCE_DATA) { + if(!rangeptr) + retval = writeValueAttributeWithoutRange(node, &adjustedValue); + else + retval = writeValueAttributeWithRange(node, &adjustedValue, rangeptr); #ifdef UA_ENABLE_HISTORIZING - /* node is a UA_VariableNode*, but it may also point to a UA_VariableTypeNode */ - /* UA_VariableTypeNode doesn't have the historizing attribute */ - if(retval == UA_STATUSCODE_GOOD && node->nodeClass == UA_NODECLASS_VARIABLE && - server->config.historyDatabase.setValue) { - UA_UNLOCK(server->serviceMutex); - server->config.historyDatabase. - setValue(server, server->config.historyDatabase.context, - &session->sessionId, session->sessionHandle, - &node->nodeId, node->historizing, &adjustedValue); - UA_LOCK(server->serviceMutex); - } + /* node is a UA_VariableNode*, but it may also point to a + UA_VariableTypeNode */ + /* UA_VariableTypeNode doesn't have the historizing attribute */ + if(retval == UA_STATUSCODE_GOOD && + node->head.nodeClass == UA_NODECLASS_VARIABLE && + server->config.historyDatabase.setValue) { + UA_UNLOCK(&server->serviceMutex); + server->config.historyDatabase. + setValue(server, server->config.historyDatabase.context, + &session->sessionId, session->sessionHandle, + &node->head.nodeId, node->historizing, &adjustedValue); + UA_LOCK(&server->serviceMutex); + } #endif - /* Callback after writing */ - if(retval == UA_STATUSCODE_GOOD && node->value.data.callback.onWrite) { - UA_UNLOCK(server->serviceMutex) - node->value.data.callback. - onWrite(server, &session->sessionId, session->sessionHandle, - &node->nodeId, node->context, rangeptr, &adjustedValue); - UA_LOCK(server->serviceMutex); + /* Callback after writing */ + if(retval == UA_STATUSCODE_GOOD && node->value.data.callback.onWrite) { + UA_UNLOCK(&server->serviceMutex); + node->value.data.callback. + onWrite(server, &session->sessionId, session->sessionHandle, + &node->head.nodeId, node->head.context, + rangeptr, &adjustedValue); + UA_LOCK(&server->serviceMutex); - } - } else { - if(node->value.dataSource.write) { - UA_UNLOCK(server->serviceMutex); - retval = node->value.dataSource. - write(server, &session->sessionId, session->sessionHandle, - &node->nodeId, node->context, rangeptr, &adjustedValue); - UA_LOCK(server->serviceMutex); - } else { - retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; - } + } + } else { + if(node->value.dataSource.write) { + UA_UNLOCK(&server->serviceMutex); + retval = node->value.dataSource. + write(server, &session->sessionId, session->sessionHandle, + &node->head.nodeId, node->head.context, + rangeptr, &adjustedValue); + UA_LOCK(&server->serviceMutex); + } else { + retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; + } + } + break; + case UA_VALUEBACKENDTYPE_INTERNAL: + break; + case UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK: + break; + case UA_VALUEBACKENDTYPE_EXTERNAL: + if(node->valueBackend.backend.external.callback.userWrite == NULL){ + if(rangeptr && rangeptr->dimensions != NULL) + UA_free(rangeptr->dimensions); + return UA_STATUSCODE_BADWRITENOTSUPPORTED; + } + retval = node->valueBackend.backend.external.callback. + userWrite(server, &session->sessionId, session->sessionHandle, + &node->head.nodeId, node->head.context, + rangeptr, &adjustedValue); + break; } /* Clean up */ - if(rangeptr) - UA_free(range.dimensions); + if(rangeptr && rangeptr->dimensions != NULL) + UA_free(rangeptr->dimensions); return retval; } static UA_StatusCode writeIsAbstractAttribute(UA_Node *node, UA_Boolean value) { - switch(node->nodeClass) { + switch(node->head.nodeClass) { case UA_NODECLASS_OBJECTTYPE: - ((UA_ObjectTypeNode*)node)->isAbstract = value; + node->objectTypeNode.isAbstract = value; break; case UA_NODECLASS_REFERENCETYPE: - ((UA_ReferenceTypeNode*)node)->isAbstract = value; + node->referenceTypeNode.isAbstract = value; break; case UA_NODECLASS_VARIABLETYPE: - ((UA_VariableTypeNode*)node)->isAbstract = value; + node->variableTypeNode.isAbstract = value; break; case UA_NODECLASS_DATATYPE: - ((UA_DataTypeNode*)node)->isAbstract = value; + node->dataTypeNode.isAbstract = value; break; default: return UA_STATUSCODE_BADNODECLASSINVALID; @@ -36069,7 +39030,7 @@ writeIsAbstractAttribute(UA_Node *node, UA_Boolean value) { } #define CHECK_NODECLASS_WRITE(CLASS) \ - if((node->nodeClass & (CLASS)) == 0) { \ + if((node->head.nodeClass & (CLASS)) == 0) { \ retval = UA_STATUSCODE_BADNODECLASSINVALID; \ break; \ } @@ -36082,7 +39043,7 @@ writeIsAbstractAttribute(UA_Node *node, UA_Boolean value) { #define GET_NODETYPE \ type = (const UA_VariableTypeNode*) \ - getNodeType(server, node); \ + getNodeType(server, &node->head); \ if(!type) { \ retval = UA_STATUSCODE_BADTYPEMISMATCH; \ break; \ @@ -36101,15 +39062,49 @@ updateLocalizedText(const UA_LocalizedText *source, UA_LocalizedText *target) { return UA_STATUSCODE_GOOD; } +/* Trigger sampling if a MonitoredItem surveils the attribute with no sampling + * interval */ +#ifdef UA_ENABLE_SUBSCRIPTIONS +static void +triggerImmediateDataChange(UA_Server *server, UA_Session *session, + UA_Node *node, const UA_WriteValue *wvalue) { + for(UA_MonitoredItem *mon = node->head.monitoredItems; mon != NULL; mon = mon->next) { + if(mon->itemToMonitor.attributeId != wvalue->attributeId) + continue; + UA_DataValue value; + UA_DataValue_init(&value); + ReadWithNode(node, server, session, mon->timestampsToReturn, + &mon->itemToMonitor, &value); + UA_Subscription *sub = mon->subscription; + UA_StatusCode res = sampleCallbackWithValue(server, sub, mon, &value); + if(res != UA_STATUSCODE_GOOD) { + UA_DataValue_clear(&value); + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %" PRIi32 " | " + "Sampling returned the statuscode %s", + mon->monitoredItemId, + UA_StatusCode_name(res)); + } + } +} +#endif + /* This function implements the main part of the write service and operates on a copy of the node (not in single-threaded mode). */ static UA_StatusCode copyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) { + UA_assert(session != NULL); const void *value = wvalue->value.value.data; - UA_UInt32 userWriteMask = getUserWriteMask(server, session, node); + UA_UInt32 userWriteMask = getUserWriteMask(server, session, &node->head); UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_LOG_NODEID_DEBUG(&node->head.nodeId, + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Write attribute %"PRIi32 " of Node %.*s", + wvalue->attributeId, (int)nodeIdStr.length, + nodeIdStr.data)); + const UA_VariableTypeNode *type; switch(wvalue->attributeId) { @@ -36125,17 +39120,19 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session, case UA_ATTRIBUTEID_DISPLAYNAME: CHECK_USERWRITEMASK(UA_WRITEMASK_DISPLAYNAME); CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); - retval = updateLocalizedText((const UA_LocalizedText *)value, &node->displayName); + retval = updateLocalizedText((const UA_LocalizedText *)value, + &node->head.displayName); break; case UA_ATTRIBUTEID_DESCRIPTION: CHECK_USERWRITEMASK(UA_WRITEMASK_DESCRIPTION); CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); - retval = updateLocalizedText((const UA_LocalizedText *)value, &node->description); + retval = updateLocalizedText((const UA_LocalizedText *)value, + &node->head.description); break; case UA_ATTRIBUTEID_WRITEMASK: CHECK_USERWRITEMASK(UA_WRITEMASK_WRITEMASK); CHECK_DATATYPE_SCALAR(UINT32); - node->writeMask = *(const UA_UInt32*)value; + node->head.writeMask = *(const UA_UInt32*)value; break; case UA_ATTRIBUTEID_ISABSTRACT: CHECK_USERWRITEMASK(UA_WRITEMASK_ISABSTRACT); @@ -36146,42 +39143,42 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session, CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_SYMMETRIC); CHECK_DATATYPE_SCALAR(BOOLEAN); - ((UA_ReferenceTypeNode*)node)->symmetric = *(const UA_Boolean*)value; + node->referenceTypeNode.symmetric = *(const UA_Boolean*)value; break; case UA_ATTRIBUTEID_INVERSENAME: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_INVERSENAME); CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); retval = updateLocalizedText((const UA_LocalizedText *)value, - &((UA_ReferenceTypeNode*)node)->inverseName); + &node->referenceTypeNode.inverseName); break; case UA_ATTRIBUTEID_CONTAINSNOLOOPS: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW); CHECK_USERWRITEMASK(UA_WRITEMASK_CONTAINSNOLOOPS); CHECK_DATATYPE_SCALAR(BOOLEAN); - ((UA_ViewNode*)node)->containsNoLoops = *(const UA_Boolean*)value; + node->viewNode.containsNoLoops = *(const UA_Boolean*)value; break; case UA_ATTRIBUTEID_EVENTNOTIFIER: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); CHECK_USERWRITEMASK(UA_WRITEMASK_EVENTNOTIFIER); CHECK_DATATYPE_SCALAR(BYTE); - if(node->nodeClass == UA_NODECLASS_VIEW) { - ((UA_ViewNode*)node)->eventNotifier = *(const UA_Byte*)value; + if(node->head.nodeClass == UA_NODECLASS_VIEW) { + node->viewNode.eventNotifier = *(const UA_Byte*)value; } else { - ((UA_ObjectNode*)node)->eventNotifier = *(const UA_Byte*)value; + node->objectNode.eventNotifier = *(const UA_Byte*)value; } break; case UA_ATTRIBUTEID_VALUE: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); - if(node->nodeClass == UA_NODECLASS_VARIABLE) { + if(node->head.nodeClass == UA_NODECLASS_VARIABLE) { /* The access to a value variable is granted via the AccessLevel * and UserAccessLevel attributes */ - UA_Byte accessLevel = getAccessLevel(server, session, (const UA_VariableNode*)node); + UA_Byte accessLevel = getAccessLevel(server, session, &node->variableNode); if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) { retval = UA_STATUSCODE_BADNOTWRITABLE; break; } - accessLevel = getUserAccessLevel(server, session, (const UA_VariableNode*)node); + accessLevel = getUserAccessLevel(server, session, &node->variableNode); if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) { retval = UA_STATUSCODE_BADUSERACCESSDENIED; break; @@ -36189,15 +39186,15 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session, } else { /* UA_NODECLASS_VARIABLETYPE */ CHECK_USERWRITEMASK(UA_WRITEMASK_VALUEFORVARIABLETYPE); } - retval = writeValueAttribute(server, session, (UA_VariableNode*)node, - &wvalue->value, &wvalue->indexRange); + retval = writeNodeValueAttribute(server, session, &node->variableNode, + &wvalue->value, &wvalue->indexRange); break; case UA_ATTRIBUTEID_DATATYPE: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_DATATYPE); CHECK_DATATYPE_SCALAR(NODEID); - GET_NODETYPE - retval = writeDataTypeAttribute(server, session, (UA_VariableNode*)node, + GET_NODETYPE; + retval = writeDataTypeAttribute(server, session, &node->variableNode, type, (const UA_NodeId*)value); UA_NODESTORE_RELEASE(server, (const UA_Node*)type); break; @@ -36205,8 +39202,8 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session, CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_VALUERANK); CHECK_DATATYPE_SCALAR(INT32); - GET_NODETYPE - retval = writeValueRankAttribute(server, session, (UA_VariableNode*)node, + GET_NODETYPE; + retval = writeValueRankAttribute(server, session, &node->variableNode, type, *(const UA_Int32*)value); UA_NODESTORE_RELEASE(server, (const UA_Node*)type); break; @@ -36214,8 +39211,8 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session, CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); CHECK_USERWRITEMASK(UA_WRITEMASK_ARRRAYDIMENSIONS); CHECK_DATATYPE_ARRAY(UINT32); - GET_NODETYPE - retval = writeArrayDimensionsAttribute(server, session, (UA_VariableNode*)node, + GET_NODETYPE; + retval = writeArrayDimensionsAttribute(server, session, &node->variableNode, type, wvalue->value.value.arrayLength, (UA_UInt32 *)wvalue->value.value.data); UA_NODESTORE_RELEASE(server, (const UA_Node*)type); @@ -36224,51 +39221,64 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session, CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVEL); CHECK_DATATYPE_SCALAR(BYTE); - ((UA_VariableNode*)node)->accessLevel = *(const UA_Byte*)value; + node->variableNode.accessLevel = *(const UA_Byte*)value; break; case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_USERWRITEMASK(UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL); CHECK_DATATYPE_SCALAR(DOUBLE); - ((UA_VariableNode*)node)->minimumSamplingInterval = *(const UA_Double*)value; + node->variableNode.minimumSamplingInterval = *(const UA_Double*)value; break; case UA_ATTRIBUTEID_HISTORIZING: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_USERWRITEMASK(UA_WRITEMASK_HISTORIZING); CHECK_DATATYPE_SCALAR(BOOLEAN); - ((UA_VariableNode*)node)->historizing = *(const UA_Boolean*)value; + node->variableNode.historizing = *(const UA_Boolean*)value; break; case UA_ATTRIBUTEID_EXECUTABLE: CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD); CHECK_USERWRITEMASK(UA_WRITEMASK_EXECUTABLE); CHECK_DATATYPE_SCALAR(BOOLEAN); - ((UA_MethodNode*)node)->executable = *(const UA_Boolean*)value; + node->methodNode.executable = *(const UA_Boolean*)value; break; default: retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; break; } - if(retval != UA_STATUSCODE_GOOD) + + /* Check if writing succeeded */ + if(retval != UA_STATUSCODE_GOOD) { UA_LOG_INFO_SESSION(&server->config.logger, session, "WriteRequest returned status code %s", UA_StatusCode_name(retval)); - return retval; + return retval; + } + + /* Trigger MonitoredItems with no SamplingInterval */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + triggerImmediateDataChange(server, session, node, wvalue); +#endif + + return UA_STATUSCODE_GOOD; } static void Operation_Write(UA_Server *server, UA_Session *session, void *context, - UA_WriteValue *wv, UA_StatusCode *result) { + const UA_WriteValue *wv, UA_StatusCode *result) { + UA_assert(session != NULL); *result = UA_Server_editNode(server, session, &wv->nodeId, - (UA_EditNodeCallback)copyAttributeIntoNode, wv); + (UA_EditNodeCallback)copyAttributeIntoNode, + (void*)(uintptr_t)wv); } void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request, UA_WriteResponse *response) { + UA_assert(session != NULL); UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing WriteRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxNodesPerWrite != 0 && request->nodesToWriteSize > server->config.maxNodesPerWrite) { @@ -36276,46 +39286,45 @@ Service_Write(UA_Server *server, UA_Session *session, return; } - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_Write, NULL, - &request->nodesToWriteSize, &UA_TYPES[UA_TYPES_WRITEVALUE], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_Write, NULL, + &request->nodesToWriteSize, + &UA_TYPES[UA_TYPES_WRITEVALUE], + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } UA_StatusCode -writeWithSession(UA_Server *server, UA_Session *session, - const UA_WriteValue *value) { - return UA_Server_editNode(server, session, &value->nodeId, - (UA_EditNodeCallback)copyAttributeIntoNode, - /* casting away const qualifier because callback uses const anyway */ - (UA_WriteValue *)(uintptr_t)value); +UA_Server_write(UA_Server *server, const UA_WriteValue *value) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_LOCK(&server->serviceMutex); + Operation_Write(server, &server->adminSession, NULL, value, &res); + UA_UNLOCK(&server->serviceMutex); + return res; } +/* Convenience function to be wrapped into inline functions */ UA_StatusCode -writeAttribute(UA_Server *server, const UA_WriteValue *value) { - UA_LOCK_ASSERT(server->serviceMutex, 1); - return UA_Server_editNode(server, &server->adminSession, &value->nodeId, - (UA_EditNodeCallback)copyAttributeIntoNode, - /* casting away const qualifier because callback uses const anyway */ - (UA_WriteValue *)(uintptr_t)value); +__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId, + const UA_AttributeId attributeId, + const UA_DataType *attr_type, const void *attr) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode res = writeAttribute(server, &server->adminSession, + nodeId, attributeId, attr, attr_type); + UA_UNLOCK(&server->serviceMutex); + return res; } +/* Internal convenience function */ UA_StatusCode -UA_Server_write(UA_Server *server, const UA_WriteValue *value) { - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = writeAttribute(server, value); - UA_UNLOCK(server->serviceMutex); - return retval; -} +writeAttribute(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, const UA_AttributeId attributeId, + const void *attr, const UA_DataType *attr_type) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); -UA_StatusCode -writeWithWriteValue(UA_Server *server, const UA_NodeId *nodeId, - const UA_AttributeId attributeId, - const UA_DataType *attr_type, - const void *attr) { - UA_LOCK_ASSERT(server->serviceMutex, 1); UA_WriteValue wvalue; UA_WriteValue_init(&wvalue); wvalue.nodeId = *nodeId; @@ -36330,19 +39339,10 @@ writeWithWriteValue(UA_Server *server, const UA_NodeId *nodeId, UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)attr, attr_type); } - return writeAttribute(server, &wvalue); -} -/* Convenience function to be wrapped into inline functions */ -UA_StatusCode -__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId, - const UA_AttributeId attributeId, - const UA_DataType *attr_type, - const void *attr) { - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = writeWithWriteValue(server, nodeId, attributeId, attr_type, attr); - UA_UNLOCK(server->serviceMutex); - return retval; + UA_StatusCode res = UA_STATUSCODE_GOOD; + Operation_Write(server, session, NULL, &wvalue, &res); + return res; } #ifdef UA_ENABLE_HISTORIZING @@ -36362,7 +39362,12 @@ void Service_HistoryRead(UA_Server *server, UA_Session *session, const UA_HistoryReadRequest *request, UA_HistoryReadResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_assert(session != NULL); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + if(server->config.historyDatabase.context == NULL) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED; + return; + } if(request->historyReadDetails.encoding != UA_EXTENSIONOBJECT_DECODED) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED; @@ -36371,31 +39376,32 @@ Service_HistoryRead(UA_Server *server, UA_Session *session, const UA_DataType *historyDataType = &UA_TYPES[UA_TYPES_HISTORYDATA]; UA_HistoryDatabase_readFunc readHistory = NULL; - switch(request->historyReadDetails.content.decoded.type->typeIndex) { - case UA_TYPES_READRAWMODIFIEDDETAILS: { - UA_ReadRawModifiedDetails *details = (UA_ReadRawModifiedDetails*) - request->historyReadDetails.content.decoded.data; - if(!details->isReadModified) { - readHistory = (UA_HistoryDatabase_readFunc)server->config.historyDatabase.readRaw; - } else { - historyDataType = &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA]; - readHistory = (UA_HistoryDatabase_readFunc)server->config.historyDatabase.readModified; - } - break; - } - case UA_TYPES_READEVENTDETAILS: - historyDataType = &UA_TYPES[UA_TYPES_HISTORYEVENT]; - readHistory = (UA_HistoryDatabase_readFunc)server->config.historyDatabase.readEvent; - break; - case UA_TYPES_READPROCESSEDDETAILS: - readHistory = (UA_HistoryDatabase_readFunc)server->config.historyDatabase.readProcessed; - break; - case UA_TYPES_READATTIMEDETAILS: - readHistory = (UA_HistoryDatabase_readFunc)server->config.historyDatabase.readAtTime; - break; - } - - if(!readHistory) { + if(request->historyReadDetails.content.decoded.type == + &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS]) { + UA_ReadRawModifiedDetails *details = (UA_ReadRawModifiedDetails*) + request->historyReadDetails.content.decoded.data; + if(!details->isReadModified) { + readHistory = (UA_HistoryDatabase_readFunc) + server->config.historyDatabase.readRaw; + } else { + historyDataType = &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA]; + readHistory = (UA_HistoryDatabase_readFunc) + server->config.historyDatabase.readModified; + } + } else if(request->historyReadDetails.content.decoded.type == + &UA_TYPES[UA_TYPES_READEVENTDETAILS]) { + historyDataType = &UA_TYPES[UA_TYPES_HISTORYEVENT]; + readHistory = (UA_HistoryDatabase_readFunc) + server->config.historyDatabase.readEvent; + } else if(request->historyReadDetails.content.decoded.type == + &UA_TYPES[UA_TYPES_READPROCESSEDDETAILS]) { + readHistory = (UA_HistoryDatabase_readFunc) + server->config.historyDatabase.readProcessed; + } else if(request->historyReadDetails.content.decoded.type == + &UA_TYPES[UA_TYPES_READATTIMEDETAILS]) { + readHistory = (UA_HistoryDatabase_readFunc) + server->config.historyDatabase.readAtTime; + } else { /* TODO handle more request->historyReadDetails.content.decoded.type types */ response->responseHeader.serviceResult = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED; return; @@ -36435,12 +39441,11 @@ Service_HistoryRead(UA_Server *server, UA_Session *session, for(size_t i = 0; i < response->resultsSize; ++i) { void * data = UA_new(historyDataType); - response->results[i].historyData.encoding = UA_EXTENSIONOBJECT_DECODED; - response->results[i].historyData.content.decoded.type = historyDataType; - response->results[i].historyData.content.decoded.data = data; + UA_ExtensionObject_setValue(&response->results[i].historyData, + data, historyDataType); historyData[i] = data; } - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); readHistory(server, server->config.historyDatabase.context, &session->sessionId, session->sessionHandle, &request->requestHeader, @@ -36449,7 +39454,7 @@ Service_HistoryRead(UA_Server *server, UA_Session *session, request->releaseContinuationPoints, request->nodesToReadSize, request->nodesToRead, response, historyData); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_free(historyData); } @@ -36457,7 +39462,8 @@ void Service_HistoryUpdate(UA_Server *server, UA_Session *session, const UA_HistoryUpdateRequest *request, UA_HistoryUpdateResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_assert(session != NULL); + UA_LOCK_ASSERT(&server->serviceMutex, 1); response->resultsSize = request->historyUpdateDetailsSize; response->results = (UA_HistoryUpdateResult*) @@ -36478,35 +39484,36 @@ Service_HistoryUpdate(UA_Server *server, UA_Session *session, const UA_DataType *updateDetailsType = request->historyUpdateDetails[i].content.decoded.type; void *updateDetailsData = request->historyUpdateDetails[i].content.decoded.data; + if(updateDetailsType == &UA_TYPES[UA_TYPES_UPDATEDATADETAILS]) { - if(server->config.historyDatabase.updateData) { - UA_UNLOCK(server->serviceMutex); - server->config.historyDatabase. - updateData(server, server->config.historyDatabase.context, - &session->sessionId, session->sessionHandle, - &request->requestHeader, - (UA_UpdateDataDetails*)updateDetailsData, - &response->results[i]); - UA_LOCK(server->serviceMutex); - } else { + if(!server->config.historyDatabase.updateData) { response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED; + continue; } + UA_UNLOCK(&server->serviceMutex); + server->config.historyDatabase. + updateData(server, server->config.historyDatabase.context, + &session->sessionId, session->sessionHandle, + &request->requestHeader, + (UA_UpdateDataDetails*)updateDetailsData, + &response->results[i]); + UA_LOCK(&server->serviceMutex); continue; } if(updateDetailsType == &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS]) { - if(server->config.historyDatabase.deleteRawModified) { - UA_UNLOCK(server->serviceMutex); - server->config.historyDatabase. - deleteRawModified(server, server->config.historyDatabase.context, - &session->sessionId, session->sessionHandle, - &request->requestHeader, - (UA_DeleteRawModifiedDetails*)updateDetailsData, - &response->results[i]); - UA_LOCK(server->serviceMutex); - } else { + if(!server->config.historyDatabase.deleteRawModified) { response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED; + continue; } + UA_UNLOCK(&server->serviceMutex); + server->config.historyDatabase. + deleteRawModified(server, server->config.historyDatabase.context, + &session->sessionId, session->sessionHandle, + &request->requestHeader, + (UA_DeleteRawModifiedDetails*)updateDetailsData, + &response->results[i]); + UA_LOCK(&server->serviceMutex); continue; } @@ -36516,21 +39523,21 @@ Service_HistoryUpdate(UA_Server *server, UA_Session *session, #endif -UA_StatusCode UA_EXPORT +UA_StatusCode UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId, const UA_QualifiedName propertyName, const UA_Variant value) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retVal = writeObjectProperty(server, objectId, propertyName, value); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retVal; } UA_StatusCode writeObjectProperty(UA_Server *server, const UA_NodeId objectId, - const UA_QualifiedName propertyName, - const UA_Variant value) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + const UA_QualifiedName propertyName, + const UA_Variant value) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_RelativePathElement rpe; UA_RelativePathElement_init(&rpe); rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); @@ -36552,8 +39559,8 @@ writeObjectProperty(UA_Server *server, const UA_NodeId objectId, return retval; } - retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, - UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); + retval = writeValueAttribute(server, &server->adminSession, + &bpr.targets[0].targetId.nodeId, &value); UA_BrowsePathResult_clear(&bpr); return retval; @@ -36566,13 +39573,13 @@ UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId UA_Variant var; UA_Variant_init(&var); UA_Variant_setScalar(&var, (void*)(uintptr_t)value, type); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = writeObjectProperty(server, objectId, propertyName, var); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_discovery.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_discovery.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -36689,7 +39696,7 @@ void Service_FindServers(UA_Server *server, UA_Session *session, const UA_FindServersRequest *request, UA_FindServersResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing FindServersRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Return the server itself? */ UA_Boolean foundSelf = false; @@ -36728,54 +39735,44 @@ void Service_FindServers(UA_Server *server, UA_Session *session, #else - /* Temporarily store all the pointers which we found to avoid reiterating - * through the list */ - size_t foundServersSize = 0; - UA_STACKARRAY(UA_RegisteredServer*, foundServers, server->discoveryManager.registeredServersSize+1); + /* Allocate enough memory, including memory for the "self" response */ + size_t maxResults = server->discoveryManager.registeredServersSize + 1; + response->servers = (UA_ApplicationDescription*)UA_Array_new(maxResults, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]); + if(!response->servers) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + /* Copy into the response. TODO: Evaluate return codes */ + size_t pos = 0; + if(foundSelf) + setApplicationDescriptionFromServer(&response->servers[pos++], server); registeredServer_list_entry* current; LIST_FOREACH(current, &server->discoveryManager.registeredServers, pointers) { - if(request->serverUrisSize) { + UA_Boolean usable = (request->serverUrisSize == 0); + if(!usable) { /* If client only requested a specific set of servers */ for(size_t i = 0; i < request->serverUrisSize; i++) { if(UA_String_equal(¤t->registeredServer.serverUri, &request->serverUris[i])) { - foundServers[foundServersSize] = ¤t->registeredServer; - foundServersSize++; + usable = true; break; } } - } else { - /* Return all registered servers */ - foundServers[foundServersSize] = ¤t->registeredServer; - foundServersSize++; } - } - - size_t allocSize = foundServersSize; - if(foundSelf) - allocSize++; - - /* Nothing to do? */ - if(allocSize == 0) - return; - /* Allocate memory */ - response->servers = (UA_ApplicationDescription*)UA_Array_new(allocSize, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]); - if(!response->servers) { - response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; - return; + if(usable) + setApplicationDescriptionFromRegisteredServer(request, &response->servers[pos++], + ¤t->registeredServer); } - response->serversSize = allocSize; - /* Copy into the response. TODO: Evaluate return codes */ - size_t pos = 0; - if(foundSelf) { - setApplicationDescriptionFromServer(&response->servers[pos++], server); - } - for(size_t i = 0; i < foundServersSize; i++) { - setApplicationDescriptionFromRegisteredServer(request, &response->servers[pos++], foundServers[i]); + /* Set the final size */ + if(pos > 0) { + response->serversSize = pos; + } else { + UA_free(response->servers); + response->servers = NULL; } - #endif } @@ -36783,10 +39780,10 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session, const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* If the client expects to see a specific endpointurl, mirror it back. If - not, clone the endpoints with the discovery url of all networklayers. */ + * not, clone the endpoints with the discovery url of all networklayers. */ const UA_String *endpointUrl = &request->endpointUrl; if(endpointUrl->length > 0) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, @@ -36797,33 +39794,6 @@ Service_GetEndpoints(UA_Server *server, UA_Session *session, "Processing GetEndpointsRequest with an empty endpointUrl"); } - /* test if the supported binary profile shall be returned */ - size_t reSize = sizeof(UA_Boolean) * server->config.endpointsSize; - UA_STACKARRAY(UA_Boolean, relevant_endpoints, reSize); - memset(relevant_endpoints, 0, reSize); - size_t relevant_count = 0; - if(request->profileUrisSize == 0) { - for(size_t j = 0; j < server->config.endpointsSize; ++j) - relevant_endpoints[j] = true; - relevant_count = server->config.endpointsSize; - } else { - for(size_t j = 0; j < server->config.endpointsSize; ++j) { - for(size_t i = 0; i < request->profileUrisSize; ++i) { - if(!UA_String_equal(&request->profileUris[i], - &server->config.endpoints[j].transportProfileUri)) - continue; - relevant_endpoints[j] = true; - ++relevant_count; - break; - } - } - } - - if(relevant_count == 0) { - response->endpointsSize = 0; - return; - } - /* Clone the endpoint for each networklayer? */ size_t clone_times = 1; UA_Boolean nl_endpointurl = false; @@ -36832,41 +39802,62 @@ Service_GetEndpoints(UA_Server *server, UA_Session *session, nl_endpointurl = true; } - response->endpoints = - (UA_EndpointDescription*)UA_Array_new(relevant_count * clone_times, - &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); + /* Allocate enough memory */ + response->endpoints = (UA_EndpointDescription*) + UA_Array_new(server->config.endpointsSize * clone_times, + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); if(!response->endpoints) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } - response->endpointsSize = relevant_count * clone_times; - size_t k = 0; - UA_StatusCode retval; - for(size_t i = 0; i < clone_times; ++i) { - if(nl_endpointurl) - endpointUrl = &server->config.networkLayers[i].discoveryUrl; - for(size_t j = 0; j < server->config.endpointsSize; ++j) { - if(!relevant_endpoints[j]) - continue; - retval = UA_EndpointDescription_copy(&server->config.endpoints[j], - &response->endpoints[k]); - if(retval != UA_STATUSCODE_GOOD) - goto error; - retval = UA_String_copy(endpointUrl, &response->endpoints[k].endpointUrl); - if(retval != UA_STATUSCODE_GOOD) - goto error; - retval = UA_Array_copy(endpointUrl, 1, - (void**)&response->endpoints[k].server.discoveryUrls, - &UA_TYPES[UA_TYPES_STRING]); + size_t pos = 0; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + for(size_t j = 0; j < server->config.endpointsSize; ++j) { + /* Test if the supported binary profile shall be returned */ + UA_Boolean usable = (request->profileUrisSize == 0); + if(!usable) { + for(size_t i = 0; i < request->profileUrisSize; ++i) { + if(!UA_String_equal(&request->profileUris[i], + &server->config.endpoints[j].transportProfileUri)) + continue; + usable = true; + break; + } + } + if(!usable) + continue; + + /* Copy into the results */ + for(size_t i = 0; i < clone_times; ++i) { + retval |= UA_EndpointDescription_copy(&server->config.endpoints[j], + &response->endpoints[pos]); + UA_String_clear(&response->endpoints[pos].endpointUrl); + UA_Array_delete(response->endpoints[pos].server.discoveryUrls, + response->endpoints[pos].server.discoveryUrlsSize, + &UA_TYPES[UA_TYPES_STRING]); + response->endpoints[pos].server.discoveryUrls = NULL; + response->endpoints[pos].server.discoveryUrlsSize = 0; + if(nl_endpointurl) + endpointUrl = &server->config.networkLayers[i].discoveryUrl; + retval |= UA_String_copy(endpointUrl, &response->endpoints[pos].endpointUrl); + retval |= UA_Array_copy(endpointUrl, 1, + (void**)&response->endpoints[pos].server.discoveryUrls, + &UA_TYPES[UA_TYPES_STRING]); if(retval != UA_STATUSCODE_GOOD) goto error; - response->endpoints[k].server.discoveryUrlsSize = 1; - ++k; + response->endpoints[pos].server.discoveryUrlsSize = 1; + pos++; } } - return; + UA_assert(pos <= server->config.endpointsSize * clone_times); + response->endpointsSize = pos; + + /* Clean up the memory of there are no usable results */ + if(pos > 0) + return; + error: response->responseHeader.serviceResult = retval; UA_Array_delete(response->endpoints, response->endpointsSize, @@ -36888,7 +39879,8 @@ process_RegisterServer(UA_Server *server, UA_Session *session, UA_StatusCode **responseConfigurationResults, size_t *responseDiagnosticInfosSize, UA_DiagnosticInfo *responseDiagnosticInfos) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + /* Find the server from the request in the registered list */ registeredServer_list_entry* current; registeredServer_list_entry *registeredServer_entry = NULL; @@ -36965,7 +39957,7 @@ process_RegisterServer(UA_Server *server, UA_Session *session, } #ifdef UA_ENABLE_DISCOVERY_MULTICAST - if(server->config.discovery.mdnsEnable) { + if(server->config.mdnsEnabled) { for(size_t i = 0; i < requestServer->discoveryUrlsSize; i++) { /* create TXT if is online and first index, delete TXT if is offline and last index */ UA_Boolean updateTxt = (requestServer->isOnline && i==0) || @@ -36989,24 +39981,18 @@ process_RegisterServer(UA_Server *server, UA_Session *session, } if(server->discoveryManager.registerServerCallback) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); server->discoveryManager. registerServerCallback(requestServer, server->discoveryManager.registerServerCallbackData); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); } // server found, remove from list LIST_REMOVE(registeredServer_entry, pointers); UA_RegisteredServer_clear(®isteredServer_entry->registeredServer); -#if UA_MULTITHREADING >= 200 - UA_atomic_subSize(&server->discoveryManager.registeredServersSize, 1); - registeredServer_entry->delayedCleanup.callback = NULL; /* only free the structure */ - UA_WorkQueue_enqueueDelayed(&server->workQueue, ®isteredServer_entry->delayedCleanup); -#else UA_free(registeredServer_entry); server->discoveryManager.registeredServersSize--; -#endif responseHeader->serviceResult = UA_STATUSCODE_GOOD; return; } @@ -37025,11 +40011,7 @@ process_RegisterServer(UA_Server *server, UA_Session *session, } LIST_INSERT_HEAD(&server->discoveryManager.registeredServers, registeredServer_entry, pointers); -#if UA_MULTITHREADING >= 200 UA_atomic_addSize(&server->discoveryManager.registeredServersSize, 1); -#else - server->discoveryManager.registeredServersSize++; -#endif } else { UA_RegisteredServer_clear(®isteredServer_entry->registeredServer); } @@ -37039,11 +40021,11 @@ process_RegisterServer(UA_Server *server, UA_Session *session, // registered before, then crashed, restarts and registeres again. In that case the entry is not deleted // and the callback would not be called. if(server->discoveryManager.registerServerCallback) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); server->discoveryManager. registerServerCallback(requestServer, server->discoveryManager.registerServerCallbackData); - UA_LOCK(server->serviceMutex) + UA_LOCK(&server->serviceMutex); } // copy the data from the request into the list @@ -37057,7 +40039,7 @@ void Service_RegisterServer(UA_Server *server, UA_Session *session, UA_RegisterServerResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing RegisterServerRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); process_RegisterServer(server, session, &request->requestHeader, &request->server, 0, NULL, &response->responseHeader, 0, NULL, 0, NULL); } @@ -37067,7 +40049,7 @@ void Service_RegisterServer2(UA_Server *server, UA_Session *session, UA_RegisterServer2Response *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing RegisterServer2Request"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); process_RegisterServer(server, session, &request->requestHeader, &request->server, request->discoveryConfigurationSize, request->discoveryConfiguration, &response->responseHeader, &response->configurationResultsSize, @@ -37083,8 +40065,8 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) { UA_DateTime timedOut = nowMonotonic; // registration is timed out if lastSeen is older than 60 minutes (default // value, can be modified by user). - if(server->config.discovery.cleanupTimeout) - timedOut -= server->config.discovery.cleanupTimeout*UA_DATETIME_SEC; + if(server->config.discoveryCleanupTimeout) + timedOut -= server->config.discoveryCleanupTimeout * UA_DATETIME_SEC; registeredServer_list_entry* current, *temp; LIST_FOREACH_SAFE(current, &server->discoveryManager.registeredServers, pointers, temp) { @@ -37108,7 +40090,7 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) { } #endif - if(semaphoreDeleted || (server->config.discovery.cleanupTimeout && + if(semaphoreDeleted || (server->config.discoveryCleanupTimeout && current->lastSeen < timedOut)) { if(semaphoreDeleted) { UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER, @@ -37127,14 +40109,8 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) { } LIST_REMOVE(current, pointers); UA_RegisteredServer_clear(¤t->registeredServer); -#if UA_MULTITHREADING >= 200 - UA_atomic_subSize(&server->discoveryManager.registeredServersSize, 1); - current->delayedCleanup.callback = NULL; /* Only free the structure */ - UA_WorkQueue_enqueueDelayed(&server->workQueue, ¤t->delayedCleanup); -#else UA_free(current); server->discoveryManager.registeredServersSize--; -#endif } } } @@ -37151,7 +40127,7 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) { static void periodicServerRegister(UA_Server *server, void *data) { UA_assert(data != NULL); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); struct PeriodicServerRegisterCallback *cb = (struct PeriodicServerRegisterCallback *)data; @@ -37196,7 +40172,7 @@ periodicServerRegister(UA_Server *server, void *data) { cb->this_interval = nextInterval; changeRepeatedCallbackInterval(server, cb->id, nextInterval); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return; } @@ -37211,7 +40187,7 @@ periodicServerRegister(UA_Server *server, void *data) { if(retval == UA_STATUSCODE_GOOD) cb->registered = true; } - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } UA_StatusCode @@ -37221,18 +40197,18 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, UA_Double intervalMs, UA_Double delayFirstRegisterMs, UA_UInt64 *periodicCallbackId) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); /* No valid server URL */ if(!discoveryServerUrl) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "No discovery server URL provided"); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINTERNALERROR; } if (client->connection.state != UA_CONNECTIONSTATE_CLOSED) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINVALIDSTATE; } @@ -37258,7 +40234,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, struct PeriodicServerRegisterCallback* cb = (struct PeriodicServerRegisterCallback*) UA_malloc(sizeof(struct PeriodicServerRegisterCallback)); if(!cb) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADOUTOFMEMORY; } @@ -37273,7 +40249,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, cb->discovery_server_url = (char*)UA_malloc(len+1); if (!cb->discovery_server_url) { UA_free(cb); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADOUTOFMEMORY; } memcpy(cb->discovery_server_url, discoveryServerUrl, len+1); @@ -37287,7 +40263,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, "Could not create periodic job for server register. " "StatusCode %s", UA_StatusCode_name(retval)); UA_free(cb); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -37298,7 +40274,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, if(!newEntry) { removeCallback(server, cb->id); UA_free(cb); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADOUTOFMEMORY; } newEntry->callback = cb; @@ -37307,7 +40283,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, if(periodicCallbackId) *periodicCallbackId = cb->id; - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_GOOD; } @@ -37315,21 +40291,21 @@ void UA_Server_setRegisterServerCallback(UA_Server *server, UA_Server_registerServerCallback cb, void* data) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); server->discoveryManager.registerServerCallback = cb; server->discoveryManager.registerServerCallbackData = data; - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } #endif /* UA_ENABLE_DISCOVERY */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_subscription.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_subscription.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2014-2018, 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2016-2017 (c) Florian Palm * Copyright 2015 (c) Chris Iatrou * Copyright 2015-2016 (c) Sten Grüner @@ -37346,20 +40322,34 @@ UA_Server_setRegisterServerCallback(UA_Server *server, #ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ -static UA_StatusCode +static void +setPublishingEnabled(UA_Subscription *sub, UA_Boolean publishingEnabled) { + if(sub->publishingEnabled == publishingEnabled) + return; + + sub->publishingEnabled = publishingEnabled; + +#ifdef UA_ENABLE_DIAGNOSTICS + if(publishingEnabled) + sub->enableCount++; + else + sub->disableCount++; +#endif +} + +static void setSubscriptionSettings(UA_Server *server, UA_Subscription *subscription, UA_Double requestedPublishingInterval, UA_UInt32 requestedLifetimeCount, UA_UInt32 requestedMaxKeepAliveCount, - UA_UInt32 maxNotificationsPerPublish, UA_Byte priority) { - UA_LOCK_ASSERT(server->serviceMutex, 1); - - /* deregister the callback if required */ - Subscription_unregisterPublishCallback(server, subscription); + UA_UInt32 maxNotificationsPerPublish, + UA_Byte priority) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* re-parameterize the subscription */ UA_BOUNDEDVALUE_SETWBOUNDS(server->config.publishingIntervalLimits, - requestedPublishingInterval, subscription->publishingInterval); + requestedPublishingInterval, + subscription->publishingInterval); /* check for nan*/ if(requestedPublishingInterval != requestedPublishingInterval) subscription->publishingInterval = server->config.publishingIntervalLimits.min; @@ -37374,72 +40364,89 @@ setSubscriptionSettings(UA_Server *server, UA_Subscription *subscription, maxNotificationsPerPublish > server->config.maxNotificationsPerPublish) subscription->notificationsPerPublish = server->config.maxNotificationsPerPublish; subscription->priority = priority; - - UA_StatusCode retval = Subscription_registerPublishCallback(server, subscription); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_DEBUG_SESSION(&server->config.logger, subscription->session, - "Subscription %" PRIu32 " | Could not register publish callback with error code %s", - subscription->subscriptionId, UA_StatusCode_name(retval)); - } - return retval; } void Service_CreateSubscription(UA_Server *server, UA_Session *session, const UA_CreateSubscriptionRequest *request, UA_CreateSubscriptionResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Check limits for the number of subscriptions */ if(((server->config.maxSubscriptions != 0) && - (server->numSubscriptions >= server->config.maxSubscriptions)) || + (server->subscriptionsSize >= server->config.maxSubscriptions)) || ((server->config.maxSubscriptionsPerSession != 0) && - (session->numSubscriptions >= server->config.maxSubscriptionsPerSession))) { + (session->subscriptionsSize >= server->config.maxSubscriptionsPerSession))) { response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS; return; } /* Create the subscription */ - UA_Subscription *newSubscription = UA_Subscription_new(session, response->subscriptionId); - if(!newSubscription) { + UA_Subscription *sub= UA_Subscription_new(); + if(!sub) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing CreateSubscriptionRequest failed"); response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } - UA_Session_addSubscription(server, session, newSubscription); /* Also assigns the subscription id */ - /* Set the subscription parameters */ - newSubscription->publishingEnabled = request->publishingEnabled; - UA_StatusCode retval = setSubscriptionSettings(server, newSubscription, request->requestedPublishingInterval, - request->requestedLifetimeCount, request->requestedMaxKeepAliveCount, - request->maxNotificationsPerPublish, request->priority); - + setSubscriptionSettings(server, sub, request->requestedPublishingInterval, + request->requestedLifetimeCount, + request->requestedMaxKeepAliveCount, + request->maxNotificationsPerPublish, request->priority); + setPublishingEnabled(sub, request->publishingEnabled); + sub->currentKeepAliveCount = sub->maxKeepAliveCount; /* set settings first */ + + /* Assign the SubscriptionId */ + sub->subscriptionId = ++server->lastSubscriptionId; + + /* Register the cyclic callback */ + UA_StatusCode retval = Subscription_registerPublishCallback(server, sub); if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, + "Subscription %" PRIu32 " | " + "Could not register publish callback with error code %s", + sub->subscriptionId, UA_StatusCode_name(retval)); response->responseHeader.serviceResult = retval; + UA_Subscription_delete(server, sub); return; } - newSubscription->currentKeepAliveCount = newSubscription->maxKeepAliveCount; /* set settings first */ + /* Register the subscription in the server */ + LIST_INSERT_HEAD(&server->subscriptions, sub, serverListEntry); + server->subscriptionsSize++; + + /* Update the server statistics */ + server->serverDiagnosticsSummary.currentSubscriptionCount++; + server->serverDiagnosticsSummary.cumulatedSubscriptionCount++; + + /* Attach the Subscription to the session */ + UA_Session_attachSubscription(session, sub); /* Prepare the response */ - response->subscriptionId = newSubscription->subscriptionId; - response->revisedPublishingInterval = newSubscription->publishingInterval; - response->revisedLifetimeCount = newSubscription->lifeTimeCount; - response->revisedMaxKeepAliveCount = newSubscription->maxKeepAliveCount; + response->subscriptionId = sub->subscriptionId; + response->revisedPublishingInterval = sub->publishingInterval; + response->revisedLifetimeCount = sub->lifeTimeCount; + response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount; - UA_LOG_INFO_SESSION(&server->config.logger, session, "Subscription %" PRIu32 " | " - "Created the Subscription with a publishing interval of %.2f ms", - response->subscriptionId, newSubscription->publishingInterval); -} +#ifdef UA_ENABLE_DIAGNOSTICS + createSubscriptionObject(server, session, sub); +#endif + + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, sub, + "Subscription created (Publishing interval %.2fms, " + "max %lu notifications per publish)", + sub->publishingInterval, + (long unsigned)sub->notificationsPerPublish);} void Service_ModifySubscription(UA_Server *server, UA_Session *session, const UA_ModifySubscriptionRequest *request, UA_ModifySubscriptionResponse *response) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing ModifySubscriptionRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Processing ModifySubscriptionRequest"); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); if(!sub) { @@ -37447,26 +40454,50 @@ Service_ModifySubscription(UA_Server *server, UA_Session *session, return; } - UA_StatusCode retval = setSubscriptionSettings(server, sub, request->requestedPublishingInterval, - request->requestedLifetimeCount, request->requestedMaxKeepAliveCount, - request->maxNotificationsPerPublish, request->priority); + /* Store the old publishing interval */ + UA_Double oldPublishingInterval = sub->publishingInterval; + UA_Byte oldPriority = sub->priority; - if(retval != UA_STATUSCODE_GOOD) { - response->responseHeader.serviceResult = retval; - return; + /* Change the Subscription settings */ + setSubscriptionSettings(server, sub, request->requestedPublishingInterval, + request->requestedLifetimeCount, + request->requestedMaxKeepAliveCount, + request->maxNotificationsPerPublish, request->priority); + + /* Reset the subscription lifetime */ + sub->currentLifetimeCount = 0; + + /* Change the repeated callback to the new interval. This cannot fail as the + * CallbackId must exist. */ + if(sub->publishCallbackId > 0 && + sub->publishingInterval != oldPublishingInterval) + changeRepeatedCallbackInterval(server, sub->publishCallbackId, + sub->publishingInterval); + + /* If the priority has changed, re-enter the subscription to the + * priority-ordered queue in the session. */ + if(oldPriority != sub->priority) { + UA_Session_detachSubscription(server, session, sub, false); + UA_Session_attachSubscription(session, sub); } - sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */ + /* Set the response */ response->revisedPublishingInterval = sub->publishingInterval; response->revisedLifetimeCount = sub->lifeTimeCount; response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount; + + /* Update the diagnostics statistics */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->modifyCount++; +#endif } static void Operation_SetPublishingMode(UA_Server *server, UA_Session *session, - const UA_Boolean *publishingEnabled, const UA_UInt32 *subscriptionId, + const UA_Boolean *publishingEnabled, + const UA_UInt32 *subscriptionId, UA_StatusCode *result) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId); if(!sub) { *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; @@ -37474,46 +40505,52 @@ Operation_SetPublishingMode(UA_Server *server, UA_Session *session, } sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */ - sub->publishingEnabled = *publishingEnabled; /* Set the publishing mode */ + setPublishingEnabled(sub, *publishingEnabled); /* Set the publishing mode */ } void Service_SetPublishingMode(UA_Server *server, UA_Session *session, const UA_SetPublishingModeRequest *request, UA_SetPublishingModeResponse *response) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing SetPublishingModeRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Processing SetPublishingModeRequest"); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_Boolean publishingEnabled = request->publishingEnabled; /* request is const */ response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_SetPublishingMode, + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_SetPublishingMode, &publishingEnabled, - &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + &request->subscriptionIdsSize, + &UA_TYPES[UA_TYPES_UINT32], + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } -void +UA_StatusCode Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishRequest *request, UA_UInt32 requestId) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing PublishRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Return an error if the session has no subscription */ - if(LIST_EMPTY(&session->serverSubscriptions)) { - sendServiceFault(session->header.channel, requestId, request->requestHeader.requestHandle, - &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], UA_STATUSCODE_BADNOSUBSCRIPTION); - return; + if(TAILQ_EMPTY(&session->subscriptions)) { + sendServiceFault(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADNOSUBSCRIPTION); + return UA_STATUSCODE_BADNOSUBSCRIPTION; } /* Handle too many subscriptions to free resources before trying to allocate * resources for the new publish request. If the limit has been reached the * oldest publish request shall be responded */ if((server->config.maxPublishReqPerSession != 0) && - (session->numPublishReq >= server->config.maxPublishReqPerSession)) { - if(!UA_Subscription_reachedPublishReqLimit(server, session)) { - sendServiceFault(session->header.channel, requestId, request->requestHeader.requestHandle, - &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], UA_STATUSCODE_BADINTERNALERROR); - return; + (session->responseQueueSize >= server->config.maxPublishReqPerSession)) { + if(!UA_Session_reachedPublishReqLimit(server, session)) { + sendServiceFault(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADINTERNALERROR); + return UA_STATUSCODE_BADINTERNALERROR; } } @@ -37521,9 +40558,10 @@ Service_Publish(UA_Server *server, UA_Session *session, UA_PublishResponseEntry *entry = (UA_PublishResponseEntry *) UA_malloc(sizeof(UA_PublishResponseEntry)); if(!entry) { - sendServiceFault(session->header.channel, requestId, request->requestHeader.requestHandle, - &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], UA_STATUSCODE_BADOUTOFMEMORY); - return; + sendServiceFault(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADOUTOFMEMORY); + return UA_STATUSCODE_BADOUTOFMEMORY; } /* Prepare the response */ @@ -37539,13 +40577,16 @@ Service_Publish(UA_Server *server, UA_Session *session, &UA_TYPES[UA_TYPES_STATUSCODE]); if(!response->results) { UA_free(entry); - sendServiceFault(session->header.channel, requestId, request->requestHeader.requestHandle, - &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], UA_STATUSCODE_BADOUTOFMEMORY); - return; + sendServiceFault(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADOUTOFMEMORY); + return UA_STATUSCODE_BADOUTOFMEMORY; } response->resultsSize = request->subscriptionAcknowledgementsSize; } + /* <--- A good StatusCode is returned from here on ---> */ + /* Delete Acknowledged Subscription Messages */ for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; ++i) { UA_SubscriptionAcknowledgement *ack = &request->subscriptionAcknowledgements[i]; @@ -37558,7 +40599,8 @@ Service_Publish(UA_Server *server, UA_Session *session, continue; } /* Remove the acked transmission from the retransmission queue */ - response->results[i] = UA_Subscription_removeRetransmissionMessage(sub, ack->sequenceNumber); + response->results[i] = + UA_Subscription_removeRetransmissionMessage(sub, ack->sequenceNumber); } /* Queue the publish response. It will be dequeued in a repeated publish @@ -37568,65 +40610,60 @@ Service_Publish(UA_Server *server, UA_Session *session, UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Queued a publication message"); /* If there are late subscriptions, the new publish request is used to - * answer them immediately. However, a single subscription that generates - * many notifications must not "starve" other late subscriptions. Therefore - * we keep track of the last subscription that got preferential treatment. - * We start searching for late subscriptions **after** the last one. */ - - UA_Subscription *immediate = NULL; - if(session->lastSeenSubscriptionId > 0) { - LIST_FOREACH(immediate, &session->serverSubscriptions, listEntry) { - if(immediate->subscriptionId == session->lastSeenSubscriptionId) { - immediate = LIST_NEXT(immediate, listEntry); - break; - } - } - } + * answer them immediately. Late subscriptions with higher priority are + * considered earlier. However, a single subscription that generates many + * notifications must not "starve" other late subscriptions. Hence we move + * it to the end of the queue for the subscriptions of that priority. */ + UA_Subscription *late = NULL; + TAILQ_FOREACH(late, &session->subscriptions, sessionListEntry) { + if(late->state != UA_SUBSCRIPTIONSTATE_LATE) + continue; - /* If no entry was found, start at the beginning and don't restart */ - UA_Boolean found = false; - if(!immediate) - immediate = LIST_FIRST(&session->serverSubscriptions); - else - found = true; + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, late, + "Send PublishResponse on a late subscription"); + UA_Subscription_publish(server, late); - repeat: - while(immediate) { - if(immediate->state == UA_SUBSCRIPTIONSTATE_LATE) { - session->lastSeenSubscriptionId = immediate->subscriptionId; - UA_LOG_DEBUG_SESSION(&server->config.logger, session, - "Subscription %" PRIu32 " | Response on a late subscription", - immediate->subscriptionId); - UA_Subscription_publish(server, immediate); - return; - } - immediate = LIST_NEXT(immediate, listEntry); - } + /* The subscription was detached from the session during publish? */ + if(!late->session) + break; - /* Restart at the beginning of the list */ - if(found) { - immediate = LIST_FIRST(&session->serverSubscriptions); - found = false; - goto repeat; + /* Find the first element with smaller priority. If there is none, + * insert at the end. */ + UA_Subscription *after = TAILQ_NEXT(late, sessionListEntry); + while(after && after->priority >= late->priority) + after = TAILQ_NEXT(after, sessionListEntry); + + TAILQ_REMOVE(&session->subscriptions, late, sessionListEntry); + + if(after) + TAILQ_INSERT_BEFORE(after, late, sessionListEntry); + else + TAILQ_INSERT_TAIL(&session->subscriptions, late, sessionListEntry); + + break; } - /* No late subscription this time */ - session->lastSeenSubscriptionId = 0; + return UA_STATUSCODE_GOOD; } static void Operation_DeleteSubscription(UA_Server *server, UA_Session *session, void *_, const UA_UInt32 *subscriptionId, UA_StatusCode *result) { - *result = UA_Session_deleteSubscription(server, session, *subscriptionId); - if(*result == UA_STATUSCODE_GOOD) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, - "Subscription %" PRIu32 " | Subscription deleted", - *subscriptionId); - } else { + UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId); + if(!sub) { + *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; UA_LOG_DEBUG_SESSION(&server->config.logger, session, - "Deleting Subscription with Id %" PRIu32 " failed with error code %s", + "Deleting Subscription with Id %" PRIu32 + " failed with error code %s", *subscriptionId, UA_StatusCode_name(*result)); + return; } + + UA_Subscription_delete(server, sub); + *result = UA_STATUSCODE_GOOD; + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Subscription %" PRIu32 " | Subscription deleted", + *subscriptionId); } void @@ -37635,20 +40672,13 @@ Service_DeleteSubscriptions(UA_Server *server, UA_Session *session, UA_DeleteSubscriptionsResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing DeleteSubscriptionsRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); response->responseHeader.serviceResult = UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_DeleteSubscription, NULL, &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32], &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); - - /* The session has at least one subscription */ - if(LIST_FIRST(&session->serverSubscriptions)) - return; - - /* Send remaining publish responses if the last subscription was removed */ - UA_Subscription_answerPublishRequestsNoSubscription(server, session); } void @@ -37657,7 +40687,7 @@ Service_Republish(UA_Server *server, UA_Session *session, UA_RepublishResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing RepublishRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Get the subscription */ UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); @@ -37669,6 +40699,11 @@ Service_Republish(UA_Server *server, UA_Session *session, /* Reset the subscription lifetime */ sub->currentLifetimeCount = 0; + /* Update the subscription statistics */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->republishRequestCount++; +#endif + /* Find the notification in the retransmission queue */ UA_NotificationMessageEntry *entry; TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) { @@ -37682,11 +40717,227 @@ Service_Republish(UA_Server *server, UA_Session *session, response->responseHeader.serviceResult = UA_NotificationMessage_copy(&entry->message, &response->notificationMessage); + + /* Update the subscription statistics for the case where we return a message */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->republishMessageCount++; +#endif +} + +static UA_StatusCode +setTransferredSequenceNumbers(const UA_Subscription *sub, UA_TransferResult *result) { + /* Allocate memory */ + result->availableSequenceNumbers = (UA_UInt32*) + UA_Array_new(sub->retransmissionQueueSize, &UA_TYPES[UA_TYPES_UINT32]); + if(!result->availableSequenceNumbers) + return UA_STATUSCODE_BADOUTOFMEMORY; + result->availableSequenceNumbersSize = sub->retransmissionQueueSize; + + /* Copy over the sequence numbers */ + UA_NotificationMessageEntry *entry; + size_t i = 0; + TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) { + result->availableSequenceNumbers[i] = entry->message.sequenceNumber; + i++; + } + + UA_assert(i == result->availableSequenceNumbersSize); + + return UA_STATUSCODE_GOOD; +} + +static void +Operation_TransferSubscription(UA_Server *server, UA_Session *session, + const UA_Boolean *sendInitialValues, + const UA_UInt32 *subscriptionId, + UA_TransferResult *result) { + /* Get the subscription. This requires a server-wide lookup instead of the + * usual session-wide lookup. */ + UA_Subscription *sub = UA_Server_getSubscriptionById(server, *subscriptionId); + if(!sub) { + result->statusCode = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + /* Update the diagnostics statistics */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->transferRequestCount++; +#endif + + /* Is this the same session? Return the sequence numbers and do nothing else. */ + UA_Session *oldSession = sub->session; + if(oldSession == session) { + result->statusCode = setTransferredSequenceNumbers(sub, result); +#ifdef UA_ENABLE_DIAGNOSTICS + sub->transferredToSameClientCount++; +#endif + return; + } + + /* Check with AccessControl if the transfer is allowed */ + if(!server->config.accessControl.allowTransferSubscription || + !server->config.accessControl. + allowTransferSubscription(server, &server->config.accessControl, + oldSession ? &oldSession->sessionId : NULL, + oldSession ? oldSession->sessionHandle : NULL, + &session->sessionId, session->sessionHandle)) { + result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED; + return; + } + + /* Check limits for the number of subscriptions for this Session */ + if((server->config.maxSubscriptionsPerSession != 0) && + (session->subscriptionsSize >= server->config.maxSubscriptionsPerSession)) { + result->statusCode = UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS; + return; + } + + /* Allocate memory for the new subscription */ + UA_Subscription *newSub = (UA_Subscription*)UA_malloc(sizeof(UA_Subscription)); + if(!newSub) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + /* Set the available sequence numbers */ + result->statusCode = setTransferredSequenceNumbers(sub, result); + if(result->statusCode != UA_STATUSCODE_GOOD) { + UA_free(newSub); + return; + } + + /* Create an identical copy of the Subscription struct. The original + * subscription remains in place until a StatusChange notification has been + * sent. The elements for lists and queues are moved over manually to ensure + * that all backpointers are set correctly. */ + memcpy(newSub, sub, sizeof(UA_Subscription)); + + /* Register cyclic publish callback */ + result->statusCode = Subscription_registerPublishCallback(server, newSub); + if(result->statusCode != UA_STATUSCODE_GOOD) { + UA_Array_delete(result->availableSequenceNumbers, + sub->retransmissionQueueSize, &UA_TYPES[UA_TYPES_UINT32]); + result->availableSequenceNumbers = NULL; + result->availableSequenceNumbersSize = 0; + UA_free(newSub); + return; + } + + /* <-- The point of no return --> */ + + /* Move over the MonitoredItems and adjust the backpointers */ + LIST_INIT(&newSub->monitoredItems); + UA_MonitoredItem *mon, *mon_tmp; + LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, mon_tmp) { + LIST_REMOVE(mon, listEntry); + mon->subscription = newSub; + LIST_INSERT_HEAD(&newSub->monitoredItems, mon, listEntry); + } + sub->monitoredItemsSize = 0; + + /* Move over the notification queue */ + TAILQ_INIT(&newSub->notificationQueue); + UA_Notification *nn; + TAILQ_FOREACH(nn, &sub->notificationQueue, globalEntry) { + TAILQ_REMOVE(&sub->notificationQueue, nn, globalEntry); + TAILQ_INSERT_TAIL(&newSub->notificationQueue, nn, globalEntry); + } + sub->notificationQueueSize = 0; + sub->dataChangeNotifications = 0; + sub->eventNotifications = 0; + + TAILQ_INIT(&newSub->retransmissionQueue); + UA_NotificationMessageEntry *nme, *nme_tmp; + TAILQ_FOREACH_SAFE(nme, &sub->retransmissionQueue, listEntry, nme_tmp) { + TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry); + TAILQ_INSERT_TAIL(&newSub->retransmissionQueue, nme, listEntry); + if(oldSession) + oldSession->totalRetransmissionQueueSize -= 1; + sub->retransmissionQueueSize -= 1; + } + UA_assert(sub->retransmissionQueueSize == 0); + sub->retransmissionQueueSize = 0; + + /* Add to the server */ + UA_assert(newSub->subscriptionId == sub->subscriptionId); + LIST_INSERT_HEAD(&server->subscriptions, newSub, serverListEntry); + server->subscriptionsSize++; + + /* Attach to the session */ + UA_Session_attachSubscription(session, newSub); + + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, newSub, "Transferred to this Session"); + + /* Set StatusChange in the original subscription and force publish. This + * also removes the Subscription, even if there was no PublishResponse + * queued to send a StatusChangeNotification. */ + sub->statusChange = UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED; + UA_Subscription_publish(server, sub); + UA_assert(sub->publishCallbackId == 0); + + /* Create notifications with the current values */ + if(*sendInitialValues) { + LIST_FOREACH(mon, &newSub->monitoredItems, listEntry) { + + /* Create only DataChange notifications */ + if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) + continue; + + /* Only if the mode is monitoring */ + if(mon->monitoringMode != UA_MONITORINGMODE_REPORTING) + continue; + + /* If a value is queued for a data MonitoredItem, the next value in + * the queue is sent in the Publish response. */ + if(mon->queueSize > 0) + continue; + + /* Create a notification with the last sampled value */ + UA_MonitoredItem_createDataChangeNotification(server, newSub, mon, + &mon->lastValue); + } + } + + /* Do not update the statistics for the number of Subscriptions here. The + * fact that we duplicate the subscription and move over the content is just + * an implementtion detail. + * server->serverDiagnosticsSummary.currentSubscriptionCount++; + * server->serverDiagnosticsSummary.cumulatedSubscriptionCount++; + * + * Update the diagnostics statistics: */ +#ifdef UA_ENABLE_DIAGNOSTICS + if(oldSession && + UA_order(&oldSession->clientDescription, + &session->clientDescription, + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]) == UA_ORDER_EQ) + sub->transferredToSameClientCount++; + else + sub->transferredToAltClientCount++; +#endif + + /* Immediately try to publish on the new Subscription. This might put it + * into the "late subscription" mode. */ + UA_Subscription_publish(server, newSub); +} + +void Service_TransferSubscriptions(UA_Server *server, UA_Session *session, + const UA_TransferSubscriptionsRequest *request, + UA_TransferSubscriptionsResponse *response) { + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Processing TransferSubscriptionsRequest"); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_TransferSubscription, + &request->sendInitialValues, + &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32], + &response->resultsSize, &UA_TYPES[UA_TYPES_TRANSFERRESULT]); } #endif /* UA_ENABLE_SUBSCRIPTIONS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_monitoreditem.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_monitoreditem.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -37703,6 +40954,10 @@ Service_Republish(UA_Server *server, UA_Session *session, * Copyright 2017 (c) Henrik Norrman * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA * Copyright 2018 (c) Fabian Arndt, Root-Core + * Copyright 2020 (c) Kalycito Infotech Private Limited + * Copyright 2021 (c) Uranik, Berisha + * Copyright 2021 (c) Ammar, Morshed + * Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner) */ @@ -37714,7 +40969,7 @@ Service_Republish(UA_Server *server, UA_Session *session, * UARange property of the variable */ static UA_StatusCode setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session, - UA_MonitoredItem *mon, UA_DataChangeFilter *filter) { + const UA_MonitoredItem *mon, UA_DataChangeFilter *filter) { /* A valid deadband? */ if(filter->deadbandValue < 0.0 || filter->deadbandValue > 100.0) return UA_STATUSCODE_BADDEADBANDFILTERINVALID; @@ -37722,7 +40977,7 @@ setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session, /* Browse for the percent range */ UA_QualifiedName qn = UA_QUALIFIEDNAME(0, "EURange"); UA_BrowsePathResult bpr = - browseSimplifiedBrowsePath(server, mon->monitoredNodeId, 1, &qn); + browseSimplifiedBrowsePath(server, mon->itemToMonitor.nodeId, 1, &qn); if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) { UA_BrowsePathResult_clear(&bpr); return UA_STATUSCODE_BADFILTERNOTALLOWED; @@ -37743,9 +40998,10 @@ setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session, } /* Compute the abs deadband */ - UA_Range* euRange = (UA_Range*)rangeVal.value.data; - UA_Double absDeadband = - (filter->deadbandValue/100.0) * (euRange->high - euRange->low); + UA_Range *euRange = (UA_Range*)rangeVal.value.data; + UA_Double absDeadband = (filter->deadbandValue/100.0) * (euRange->high - euRange->low); + + UA_DataValue_clear(&rangeVal); /* EURange invalid or NaN? */ if(absDeadband < 0.0 || absDeadband != absDeadband) { @@ -37753,25 +41009,85 @@ setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session, return UA_STATUSCODE_BADFILTERNOTALLOWED; } - mon->filter.dataChangeFilter.trigger = filter->trigger; - mon->filter.dataChangeFilter.deadbandType = UA_DEADBANDTYPE_ABSOLUTE; - mon->filter.dataChangeFilter.deadbandValue = absDeadband; + /* Adjust the original filter */ + filter->deadbandType = UA_DEADBANDTYPE_ABSOLUTE; + filter->deadbandValue = absDeadband; return UA_STATUSCODE_GOOD; } #endif /* UA_ENABLE_DA */ -static UA_StatusCode -setMonitoredItemSettings(UA_Server *server, UA_Session *session, UA_MonitoredItem *mon, - UA_MonitoringMode monitoringMode, - const UA_MonitoringParameters *params, - const UA_DataType* dataType) { - UA_LOCK_ASSERT(server->serviceMutex, 1); +void +Service_SetTriggering(UA_Server *server, UA_Session *session, + const UA_SetTriggeringRequest *request, + UA_SetTriggeringResponse *response) { + /* Nothing to do? */ + if(request->linksToRemoveSize == 0 && + request->linksToAddSize == 0) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; + return; + } - UA_StatusCode retval = UA_STATUSCODE_GOOD; + /* Get the Subscription */ + UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + /* Get the MonitoredItem */ + UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, request->triggeringItemId); + if(!mon) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + return; + } + + /* Allocate the results arrays */ + if(request->linksToRemoveSize > 0) { + response->removeResults = (UA_StatusCode*) + UA_Array_new(request->linksToRemoveSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + if(!response->removeResults) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + response->removeResultsSize = request->linksToRemoveSize; + } + + if(request->linksToAddSize> 0) { + response->addResults = (UA_StatusCode*) + UA_Array_new(request->linksToAddSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + if(!response->addResults) { + UA_Array_delete(response->removeResults, + request->linksToAddSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + response->removeResults = NULL; + response->removeResultsSize = 0; + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + response->addResultsSize = request->linksToAddSize; + } + + /* Apply the changes */ + for(size_t i = 0; i < request->linksToRemoveSize; i++) + response->removeResults[i] = + UA_MonitoredItem_removeLink(sub, mon, request->linksToRemove[i]); - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - /* Event MonitoredItem */ + for(size_t i = 0; i < request->linksToAddSize; i++) + response->addResults[i] = + UA_MonitoredItem_addLink(sub, mon, request->linksToAdd[i]); +} + +/* Verify and adjust the parameters of a MonitoredItem */ +static UA_StatusCode +checkAdjustMonitoredItemParams(UA_Server *server, UA_Session *session, + const UA_MonitoredItem *mon, + const UA_DataType* valueType, + UA_MonitoringParameters *params) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + /* Check the filter */ + if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { + /* Event MonitoredItems need a filter */ #ifndef UA_ENABLE_SUBSCRIPTIONS_EVENTS return UA_STATUSCODE_BADNOTSUPPORTED; #else @@ -37780,110 +41096,158 @@ setMonitoredItemSettings(UA_Server *server, UA_Session *session, UA_MonitoredIte return UA_STATUSCODE_BADEVENTFILTERINVALID; if(params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER]) return UA_STATUSCODE_BADEVENTFILTERINVALID; - UA_EventFilter_clear(&mon->filter.eventFilter); - retval = UA_EventFilter_copy((UA_EventFilter *)params->filter.content.decoded.data, - &mon->filter.eventFilter); #endif } else { - /* DataChange MonitoredItem */ + /* DataChange MonitoredItem. Can be "no filter" which defaults to + * triggering on Status and Value. */ if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED && - params->filter.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) { - /* Default: Look for status and value */ - UA_DataChangeFilter_clear(&mon->filter.dataChangeFilter); - mon->filter.dataChangeFilter.trigger = UA_DATACHANGETRIGGER_STATUSVALUE; - } else if(params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) { - UA_DataChangeFilter *filter = (UA_DataChangeFilter *)params->filter.content.decoded.data; + params->filter.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE && + params->filter.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY) + return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED; + + /* If the filter ExtensionObject has a body, then it must be a + * DataChangeFilter */ + if(params->filter.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY && + params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) + return UA_STATUSCODE_BADFILTERNOTALLOWED; + + /* Check the deadband and adjust if necessary. */ + if(params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) { + UA_DataChangeFilter *filter = (UA_DataChangeFilter *) + params->filter.content.decoded.data; switch(filter->deadbandType) { case UA_DEADBANDTYPE_NONE: - mon->filter.dataChangeFilter = *filter; break; case UA_DEADBANDTYPE_ABSOLUTE: - if(!dataType || !UA_DataType_isNumeric(dataType)) + if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE || + !valueType || !UA_DataType_isNumeric(valueType)) return UA_STATUSCODE_BADFILTERNOTALLOWED; - mon->filter.dataChangeFilter = *filter; break; - case UA_DEADBANDTYPE_PERCENT: #ifdef UA_ENABLE_DA - if(!dataType || !UA_DataType_isNumeric(dataType)) + case UA_DEADBANDTYPE_PERCENT: { + if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE || + !valueType || !UA_DataType_isNumeric(valueType)) return UA_STATUSCODE_BADFILTERNOTALLOWED; - retval = setAbsoluteFromPercentageDeadband(server, session, mon, filter); + /* If percentage deadband is supported, look up the range values + * and precompute as if it was an absolute deadband. */ + UA_StatusCode res = + setAbsoluteFromPercentageDeadband(server, session, mon, filter); + if(res != UA_STATUSCODE_GOOD) + return res; break; -#else - return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED; + } #endif default: return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED; } - } else { - return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED; } } - if(retval != UA_STATUSCODE_GOOD) - return retval; - - /* <-- The point of no return --> */ - - /* Unregister the callback */ - UA_MonitoredItem_unregisterSampleCallback(server, mon); - - /* Remove the old samples */ - UA_ByteString_clear(&mon->lastSampledValue); - UA_Variant_clear(&mon->lastValue); - - /* ClientHandle */ - mon->clientHandle = params->clientHandle; - - /* SamplingInterval */ - UA_Double samplingInterval = params->samplingInterval; + /* Read the minimum sampling interval for the variable. The sampling + * interval of the MonitoredItem must not be less than that. */ + if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_VALUE) { + const UA_Node *node = UA_NODESTORE_GET(server, &mon->itemToMonitor.nodeId); + if(node) { + const UA_VariableNode *vn = &node->variableNode; + if(node->head.nodeClass == UA_NODECLASS_VARIABLE && + params->samplingInterval < vn->minimumSamplingInterval) + params->samplingInterval = vn->minimumSamplingInterval; + UA_NODESTORE_RELEASE(server, node); + } + } + + /* Adjust to sampling interval to lie within the limits */ + if(params->samplingInterval <= 0.0) { + /* A sampling interval of zero is possible and indicates that the + * MonitoredItem is checked for every write operation */ + params->samplingInterval = 0.0; + } else { + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.samplingIntervalLimits, + params->samplingInterval, params->samplingInterval); + /* Check for NaN */ + if(mon->parameters.samplingInterval != mon->parameters.samplingInterval) + params->samplingInterval = server->config.samplingIntervalLimits.min; + } - if(mon->attributeId == UA_ATTRIBUTEID_VALUE) { - const UA_VariableNode *vn = (const UA_VariableNode *) - UA_NODESTORE_GET(server, &mon->monitoredNodeId); - if(vn) { - if(vn->nodeClass == UA_NODECLASS_VARIABLE && - samplingInterval < vn->minimumSamplingInterval) - samplingInterval = vn->minimumSamplingInterval; - UA_NODESTORE_RELEASE(server, (const UA_Node *)vn); + /* Adjust the maximum queue size */ +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { + /* 0 => Set to the configured maximum. Otherwise adjust with configured limits */ + if(params->queueSize == 0) { + params->queueSize = server->config.queueSizeLimits.max; + } else { + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits, + params->queueSize, params->queueSize); } + } else +#endif + { + /* 0 or 1 => queue-size 1. Otherwise adjust with configured limits */ + if(params->queueSize == 0) + params->queueSize = 1; + if(params->queueSize != 1) + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits, + params->queueSize, params->queueSize); } - UA_BOUNDEDVALUE_SETWBOUNDS(server->config.samplingIntervalLimits, - samplingInterval, mon->samplingInterval); - if(samplingInterval != samplingInterval) /* Check for nan */ - mon->samplingInterval = server->config.samplingIntervalLimits.min; + return UA_STATUSCODE_GOOD; +} - /* QueueSize */ - UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits, - params->queueSize, mon->maxQueueSize); +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS +static UA_StatusCode +checkEventFilterParam(UA_Server *server, UA_Session *session, + const UA_MonitoredItem *mon, + UA_MonitoringParameters *params){ + if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) + return UA_STATUSCODE_GOOD; - /* DiscardOldest */ - mon->discardOldest = params->discardOldest; + UA_EventFilter *eventFilter = + (UA_EventFilter *) params->filter.content.decoded.data; - /* Register sample callback if reporting is enabled */ - mon->monitoringMode = monitoringMode; - if(monitoringMode == UA_MONITORINGMODE_SAMPLING || - monitoringMode == UA_MONITORINGMODE_REPORTING) - return UA_MonitoredItem_registerSampleCallback(server, mon); + if(eventFilter == NULL) + return UA_STATUSCODE_BADEVENTFILTERINVALID; - return UA_STATUSCODE_GOOD; -} + //TODO make the maximum select clause size param an server-config parameter + if(eventFilter->selectClausesSize > 128) + return UA_STATUSCODE_BADCONFIGURATIONERROR; -static const UA_String binaryEncoding = {sizeof("Default Binary") - 1, (UA_Byte *)"Default Binary"}; + //check the where clause for logical consistency + if(eventFilter->whereClause.elementsSize != 0) { + UA_ContentFilterResult contentFilterResult; + UA_Event_staticWhereClauseValidation(server, &eventFilter->whereClause, + &contentFilterResult); + for(size_t i = 0; i < contentFilterResult.elementResultsSize; ++i) { + if(contentFilterResult.elementResults[i].statusCode != UA_STATUSCODE_GOOD){ + //ToDo currently we return the first non good status code, check if + //we can use the detailed contentFilterResult later + UA_StatusCode whereResult = + contentFilterResult.elementResults[i].statusCode; + UA_ContentFilterResult_clear(&contentFilterResult); + return whereResult; + } + } + UA_ContentFilterResult_clear(&contentFilterResult); + } + //check the select clause for logical consistency + UA_StatusCode selectClauseValidationResult[128]; + UA_Event_staticSelectClauseValidation(server,eventFilter, + selectClauseValidationResult); + for(size_t i = 0; i < eventFilter->selectClausesSize; ++i){ + //ToDo currently we return the first non good status code, check if + //we can use the detailed status code list later + if(selectClauseValidationResult[i] != UA_STATUSCODE_GOOD){ + return selectClauseValidationResult[i]; + } + } -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS -static UA_StatusCode -UA_Server_addMonitoredItemToNodeEditNodeCallback(UA_Server *server, UA_Session *session, - UA_Node *node, void *data) { - /* data is the MonitoredItem */ - /* SLIST_INSERT_HEAD */ - ((UA_MonitoredItem *)data)->next = ((UA_ObjectNode *)node)->monitoredItemQueue; - ((UA_ObjectNode *)node)->monitoredItemQueue = (UA_MonitoredItem *)data; return UA_STATUSCODE_GOOD; } #endif -/* Thread-local variables to pass additional arguments into the operation */ +static const UA_String +binaryEncoding = {sizeof("Default Binary") - 1, (UA_Byte *)"Default Binary"}; + +/* Structure to pass additional arguments into the operation */ struct createMonContext { UA_Subscription *sub; UA_TimestampsToReturn timestampsToReturn; @@ -37894,44 +41258,27 @@ struct createMonContext { }; static void -Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct createMonContext *cmc, +Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, + struct createMonContext *cmc, const UA_MonitoredItemCreateRequest *request, UA_MonitoredItemCreateResult *result) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Check available capacity */ if(cmc->sub && (((server->config.maxMonitoredItems != 0) && - (server->numMonitoredItems >= server->config.maxMonitoredItems)) || + (server->monitoredItemsSize >= server->config.maxMonitoredItems)) || ((server->config.maxMonitoredItemsPerSubscription != 0) && (cmc->sub->monitoredItemsSize >= server->config.maxMonitoredItemsPerSubscription)))) { result->statusCode = UA_STATUSCODE_BADTOOMANYMONITOREDITEMS; return; } - /* Make an example read to get errors in the itemToMonitor. Allow return - * codes "good" and "uncertain", as well as a list of statuscodes that might - * be repaired inside the data source. */ - UA_DataValue v = UA_Server_readWithSession(server, session, &request->itemToMonitor, - cmc->timestampsToReturn); - if(v.hasStatus && (v.status >> 30) > 1 && - v.status != UA_STATUSCODE_BADRESOURCEUNAVAILABLE && - v.status != UA_STATUSCODE_BADCOMMUNICATIONERROR && - v.status != UA_STATUSCODE_BADWAITINGFORINITIALDATA && - v.status != UA_STATUSCODE_BADUSERACCESSDENIED && - v.status != UA_STATUSCODE_BADNOTREADABLE && - v.status != UA_STATUSCODE_BADINDEXRANGENODATA) { - result->statusCode = v.status; - UA_DataValue_clear(&v); - return; - } - /* Check if the encoding is supported */ if(request->itemToMonitor.dataEncoding.name.length > 0 && (!UA_String_equal(&binaryEncoding, &request->itemToMonitor.dataEncoding.name) || request->itemToMonitor.dataEncoding.namespaceIndex != 0)) { result->statusCode = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED; - UA_DataValue_clear(&v); return; } @@ -37939,97 +41286,153 @@ Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct cre if(request->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE && request->itemToMonitor.dataEncoding.name.length > 0) { result->statusCode = UA_STATUSCODE_BADDATAENCODINGINVALID; + return; + } + + /* Make an example read to check the itemToMonitor. The DataSource itself + * could return a (temporary) error. This should still result in a valid + * MonitoredItem. Only a few StatusCodes are considered unrecoverable and + * lead to an abort: + * - The Node does not exist + * - The AttributeId does not match the NodeClass + * - The Session does not have sufficient access rights + * - The indicated encoding is not supported or not valid */ + UA_DataValue v = UA_Server_readWithSession(server, session, &request->itemToMonitor, + cmc->timestampsToReturn); + if(v.hasStatus && + (v.status == UA_STATUSCODE_BADNODEIDUNKNOWN || + v.status == UA_STATUSCODE_BADATTRIBUTEIDINVALID || + v.status == UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED || + v.status == UA_STATUSCODE_BADDATAENCODINGINVALID || + v.status == UA_STATUSCODE_BADINDEXRANGEINVALID + /* Part 4, 5.12.2 CreateMonitoredItems: When a user adds a monitored + * item that the user is denied read access to, the add operation for + * the item shall succeed and the bad status Bad_NotReadable or + * Bad_UserAccessDenied shall be returned in the Publish response. + * v.status == UA_STATUSCODE_BADNOTREADABLE + * v.status == UA_STATUSCODE_BADUSERACCESSDENIED + * + * The IndexRange error can change depending on the value. + * v.status == UA_STATUSCODE_BADINDEXRANGENODATA */ + )) { + result->statusCode = v.status; UA_DataValue_clear(&v); return; } + /* Adding an Event MonitoredItem */ +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + if(request->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { + /* TODO: Only remote clients can add Event-MonitoredItems at the moment */ + if(!cmc->sub) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Only remote clients can add Event-MonitoredItems"); + result->statusCode = UA_STATUSCODE_BADNOTSUPPORTED; + UA_DataValue_clear(&v); + return; + } + + /* If the 'SubscribeToEvents' bit of EventNotifier attribute is + * zero, then the object cannot be subscribed to monitor events */ + if(!v.hasValue || !v.value.data) { + result->statusCode = UA_STATUSCODE_BADINTERNALERROR; + UA_DataValue_clear(&v); + return; + } + UA_Byte eventNotifierValue = *((UA_Byte *)v.value.data); + if((eventNotifierValue & 0x01) != 1) { + result->statusCode = UA_STATUSCODE_BADNOTSUPPORTED; + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, cmc->sub, + "Could not create a MonitoredItem as the " + "'SubscribeToEvents' bit of the EventNotifier " + "attribute is not set"); + UA_DataValue_clear(&v); + return; + } + } +#endif + + const UA_DataType *valueType = v.value.type; + UA_DataValue_clear(&v); + /* Allocate the MonitoredItem */ - size_t nmsize = sizeof(UA_MonitoredItem); - if(!cmc->sub) - nmsize = sizeof(UA_LocalMonitoredItem); - UA_MonitoredItem *newMon = (UA_MonitoredItem*)UA_malloc(nmsize); + UA_MonitoredItem *newMon = NULL; + if(cmc->sub) { + newMon = (UA_MonitoredItem*)UA_malloc(sizeof(UA_MonitoredItem)); + } else { + UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*) + UA_malloc(sizeof(UA_LocalMonitoredItem)); + if(localMon) { + /* Set special values only for the LocalMonitoredItem */ + localMon->context = cmc->context; + localMon->callback.dataChangeCallback = cmc->dataChangeCallback; + } + newMon = &localMon->monitoredItem; + } if(!newMon) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; - UA_DataValue_clear(&v); return; } /* Initialize the MonitoredItem */ - UA_MonitoredItem_init(newMon, cmc->sub); - newMon->attributeId = request->itemToMonitor.attributeId; + UA_MonitoredItem_init(newMon); + newMon->subscription = cmc->sub; /* Can be NULL for local MonitoredItems */ newMon->timestampsToReturn = cmc->timestampsToReturn; - UA_StatusCode retval = UA_STATUSCODE_GOOD; - retval |= UA_NodeId_copy(&request->itemToMonitor.nodeId, &newMon->monitoredNodeId); - retval |= UA_String_copy(&request->itemToMonitor.indexRange, &newMon->indexRange); - retval |= setMonitoredItemSettings(server, session, newMon, request->monitoringMode, - &request->requestedParameters, v.value.type); - UA_DataValue_clear(&v); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_INFO_SESSION(&server->config.logger, session, - "Subscription %" PRIu32 " | Could not create a MonitoredItem " - "with StatusCode %s", cmc->sub ? cmc->sub->subscriptionId : 0, - UA_StatusCode_name(retval)); - result->statusCode = retval; - UA_MonitoredItem_delete(server, newMon); - return; - } - - /* Add to the subscriptions or the local MonitoredItems */ - if(cmc->sub) { - newMon->monitoredItemId = ++cmc->sub->lastMonitoredItemId; - UA_Subscription_addMonitoredItem(server, cmc->sub, newMon); + result->statusCode |= UA_ReadValueId_copy(&request->itemToMonitor, + &newMon->itemToMonitor); + result->statusCode |= UA_MonitoringParameters_copy(&request->requestedParameters, + &newMon->parameters); + result->statusCode |= checkAdjustMonitoredItemParams(server, session, newMon, + valueType, &newMon->parameters); #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(newMon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - /* Insert the monitored item into the node's queue */ - UA_Server_editNode(server, NULL, &newMon->monitoredNodeId, - UA_Server_addMonitoredItemToNodeEditNodeCallback, newMon); - } + result->statusCode |= checkEventFilterParam(server, session, newMon, + &newMon->parameters); #endif - } else { - //TODO support events for local monitored items - UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)newMon; - localMon->context = cmc->context; - localMon->callback.dataChangeCallback = cmc->dataChangeCallback; - newMon->monitoredItemId = ++server->lastLocalMonitoredItemId; - LIST_INSERT_HEAD(&server->localMonitoredItems, newMon, listEntry); + if(result->statusCode != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, cmc->sub, + "Could not create a MonitoredItem " + "with StatusCode %s", + UA_StatusCode_name(result->statusCode)); + UA_MonitoredItem_delete(server, newMon); + return; } - /* Register MonitoredItem in userland */ - if(server->config.monitoredItemRegisterCallback) { - void *targetContext = NULL; - getNodeContext(server, request->itemToMonitor.nodeId, &targetContext); - UA_UNLOCK(server->serviceMutex); - server->config.monitoredItemRegisterCallback(server, &session->sessionId, - session->sessionHandle, - &request->itemToMonitor.nodeId, - targetContext, newMon->attributeId, false); - UA_LOCK(server->serviceMutex); - newMon->registered = true; - } + /* Initialize the value status so the first sample always passes the filter */ + newMon->lastValue.hasStatus = true; + newMon->lastValue.status = ~(UA_StatusCode)0; - UA_LOG_INFO_SESSION(&server->config.logger, session, - "Subscription %" PRIu32 " | MonitoredItem %" PRIi32 " | " - "Created the MonitoredItem", - cmc->sub ? cmc->sub->subscriptionId : 0, - newMon->monitoredItemId); + /* Register the Monitoreditem in the server and subscription */ + UA_Server_registerMonitoredItem(server, newMon); - /* Create the first sample */ - if(request->monitoringMode == UA_MONITORINGMODE_REPORTING && - newMon->attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) - monitoredItem_sampleCallback(server, newMon); + /* Activate the MonitoredItem */ + result->statusCode |= + UA_MonitoredItem_setMonitoringMode(server, newMon, request->monitoringMode); + if(result->statusCode != UA_STATUSCODE_GOOD) { + UA_MonitoredItem_delete(server, newMon); + return; + } /* Prepare the response */ - result->revisedSamplingInterval = newMon->samplingInterval; - result->revisedQueueSize = newMon->maxQueueSize; + result->revisedSamplingInterval = newMon->parameters.samplingInterval; + result->revisedQueueSize = newMon->parameters.queueSize; result->monitoredItemId = newMon->monitoredItemId; + + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, cmc->sub, + "MonitoredItem %" PRIi32 " | " + "Created the MonitoredItem " + "(Sampling Interval: %.2fms, Queue Size: %lu)", + newMon->monitoredItemId, + newMon->parameters.samplingInterval, + (unsigned long)newMon->parameters.queueSize); } void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session, const UA_CreateMonitoredItemsRequest *request, UA_CreateMonitoredItemsResponse *response) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing CreateMonitoredItemsRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Processing CreateMonitoredItemsRequest"); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxMonitoredItemsPerCall != 0 && request->itemsToCreateSize > server->config.maxMonitoredItemsPerCall) { @@ -38056,9 +41459,12 @@ Service_CreateMonitoredItems(UA_Server *server, UA_Session *session, cmc.sub->currentLifetimeCount = 0; response->responseHeader.serviceResult = - UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_CreateMonitoredItem, &cmc, - &request->itemsToCreateSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], - &response->resultsSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]); + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_CreateMonitoredItem, + &cmc, &request->itemsToCreateSize, + &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], + &response->resultsSize, + &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]); } UA_MonitoredItemCreateResult @@ -38075,9 +41481,9 @@ UA_Server_createDataChangeMonitoredItem(UA_Server *server, UA_MonitoredItemCreateResult result; UA_MonitoredItemCreateResult_init(&result); - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Operation_CreateMonitoredItem(server, &server->adminSession, &cmc, &item, &result); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return result; } @@ -38092,36 +41498,69 @@ Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscri return; } + /* Make local copy of the settings */ + UA_MonitoringParameters params; + result->statusCode = + UA_MonitoringParameters_copy(&request->requestedParameters, ¶ms); + if(result->statusCode != UA_STATUSCODE_GOOD) + return; + /* Read the current value to test if filters are possible. * Can return an empty value (v.value.type == NULL). */ - UA_ReadValueId rvid; - UA_ReadValueId_init(&rvid); - rvid.nodeId = mon->monitoredNodeId; - rvid.attributeId = mon->attributeId; - rvid.indexRange = mon->indexRange; - UA_DataValue v = UA_Server_readWithSession(server, session, &rvid, mon->timestampsToReturn); - UA_StatusCode retval = setMonitoredItemSettings(server, session, mon, mon->monitoringMode, - &request->requestedParameters, - v.value.type); + UA_DataValue v = + UA_Server_readWithSession(server, session, &mon->itemToMonitor, + mon->timestampsToReturn); + + /* Verify and adjust the new parameters. This still leaves the original + * MonitoredItem untouched. */ + result->statusCode = + checkAdjustMonitoredItemParams(server, session, mon, + v.value.type, ¶ms); UA_DataValue_clear(&v); - if(retval != UA_STATUSCODE_GOOD) { - result->statusCode = retval; + if(result->statusCode != UA_STATUSCODE_GOOD) { + UA_MonitoringParameters_clear(¶ms); return; } - result->revisedSamplingInterval = mon->samplingInterval; - result->revisedQueueSize = mon->maxQueueSize; + /* Store the old sampling interval */ + UA_Double oldSamplingInterval = mon->parameters.samplingInterval; + + /* Move over the new settings */ + UA_MonitoringParameters_clear(&mon->parameters); + mon->parameters = params; + + /* Re-register the callback if necessary */ + if(oldSamplingInterval != mon->parameters.samplingInterval) { + UA_MonitoredItem_unregisterSampling(server, mon); + result->statusCode = + UA_MonitoredItem_setMonitoringMode(server, mon, mon->monitoringMode); + } + + result->revisedSamplingInterval = mon->parameters.samplingInterval; + result->revisedQueueSize = mon->parameters.queueSize; /* Remove some notifications if the queue is now too small */ UA_MonitoredItem_ensureQueueSpace(server, mon); + + /* Remove the overflow bits if the queue has now a size of 1 */ + UA_MonitoredItem_removeOverflowInfoBits(mon); + + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %" PRIi32 " | " + "Modified the MonitoredItem " + "(Sampling Interval: %fms, Queue Size: %lu)", + mon->monitoredItemId, + mon->parameters.samplingInterval, + (unsigned long)mon->queueSize); } void Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session, const UA_ModifyMonitoredItemsRequest *request, UA_ModifyMonitoredItemsResponse *response) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing ModifyMonitoredItemsRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Processing ModifyMonitoredItemsRequest"); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxMonitoredItemsPerCall != 0 && request->itemsToModifySize > server->config.maxMonitoredItemsPerCall) { @@ -38146,9 +41585,11 @@ Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session, response->responseHeader.serviceResult = UA_Server_processServiceOperations(server, session, - (UA_ServiceOperation)Operation_ModifyMonitoredItem, sub, - &request->itemsToModifySize, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], - &response->resultsSize, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]); + (UA_ServiceOperation)Operation_ModifyMonitoredItem, + sub, &request->itemsToModifySize, + &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], + &response->resultsSize, + &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]); } struct setMonitoringContext { @@ -38165,72 +41606,7 @@ Operation_SetMonitoringMode(UA_Server *server, UA_Session *session, *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; return; } - UA_Subscription *sub = mon->subscription; - - /* Check if the MonitoringMode is valid or not */ - if(smc->monitoringMode > UA_MONITORINGMODE_REPORTING) { - *result = UA_STATUSCODE_BADMONITORINGMODEINVALID; - return; - } - - /* Nothing has changed */ - if(mon->monitoringMode == smc->monitoringMode) - return; - - mon->monitoringMode = smc->monitoringMode; - - /* When reporting is enabled, put all notifications that were already - * sampled into the global queue of the subscription. When sampling is - * enabled, remove all notifications from the global queue. !!! This needs - * to be the same operation as in UA_Notification_enqueue !!! */ - if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) { - UA_Notification *notification; - TAILQ_FOREACH(notification, &mon->queue, listEntry) { - TAILQ_INSERT_TAIL(&sub->notificationQueue, notification, globalEntry); - ++sub->notificationQueueSize; -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - ++sub->eventNotifications; - } else -#endif - { - ++sub->dataChangeNotifications; - } - } - /* Register the sampling callback with an interval */ - *result = UA_MonitoredItem_registerSampleCallback(server, mon); - } else if(mon->monitoringMode == UA_MONITORINGMODE_SAMPLING) { - UA_Notification *notification; - TAILQ_FOREACH(notification, &mon->queue, listEntry) { - TAILQ_REMOVE(&sub->notificationQueue, notification, globalEntry); - TAILQ_NEXT(notification, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; - --sub->notificationQueueSize; -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - --sub->eventNotifications; - } else -#endif - { - --sub->dataChangeNotifications; - } - } - /* Register the sampling callback with an interval */ - *result = UA_MonitoredItem_registerSampleCallback(server, mon); - } else { - /* UA_MONITORINGMODE_DISABLED */ - UA_MonitoredItem_unregisterSampleCallback(server, mon); - - /* Setting the mode to DISABLED or SAMPLING causes all queued Notifications to be deleted */ - UA_Notification *notification, *notification_tmp; - TAILQ_FOREACH_SAFE(notification, &mon->queue, listEntry, notification_tmp) { - UA_Notification_dequeue(server, notification); - UA_Notification_delete(notification); - } - - /* Initialize lastSampledValue */ - UA_ByteString_clear(&mon->lastSampledValue); - UA_Variant_clear(&mon->lastValue); - } + *result = UA_MonitoredItem_setMonitoringMode(server, mon, smc->monitoringMode); } void @@ -38238,7 +41614,7 @@ Service_SetMonitoringMode(UA_Server *server, UA_Session *session, const UA_SetMonitoringModeRequest *request, UA_SetMonitoringModeResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing SetMonitoringMode"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxMonitoredItemsPerCall != 0 && request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) { @@ -38259,15 +41635,23 @@ Service_SetMonitoringMode(UA_Server *server, UA_Session *session, smc.monitoringMode = request->monitoringMode; response->responseHeader.serviceResult = UA_Server_processServiceOperations(server, session, - (UA_ServiceOperation)Operation_SetMonitoringMode, &smc, - &request->monitoredItemIdsSize, &UA_TYPES[UA_TYPES_UINT32], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + (UA_ServiceOperation)Operation_SetMonitoringMode, + &smc, &request->monitoredItemIdsSize, + &UA_TYPES[UA_TYPES_UINT32], + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } static void Operation_DeleteMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub, const UA_UInt32 *monitoredItemId, UA_StatusCode *result) { - *result = UA_Subscription_deleteMonitoredItem(server, sub, *monitoredItemId); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, *monitoredItemId); + if(!mon) { + *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + return; + } + UA_MonitoredItem_delete(server, mon); } void @@ -38276,7 +41660,7 @@ Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session, UA_DeleteMonitoredItemsResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing DeleteMonitoredItemsRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxMonitoredItemsPerCall != 0 && request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) { @@ -38296,30 +41680,31 @@ Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session, response->responseHeader.serviceResult = UA_Server_processServiceOperations(server, session, - (UA_ServiceOperation)Operation_DeleteMonitoredItem, sub, - &request->monitoredItemIdsSize, &UA_TYPES[UA_TYPES_UINT32], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + (UA_ServiceOperation)Operation_DeleteMonitoredItem, + sub, &request->monitoredItemIdsSize, + &UA_TYPES[UA_TYPES_UINT32], + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } UA_StatusCode UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId) { - UA_LOCK(server->serviceMutex); - UA_MonitoredItem *mon; - LIST_FOREACH(mon, &server->localMonitoredItems, listEntry) { + UA_LOCK(&server->serviceMutex); + UA_MonitoredItem *mon, *mon_tmp; + LIST_FOREACH_SAFE(mon, &server->localMonitoredItems, listEntry, mon_tmp) { if(mon->monitoredItemId != monitoredItemId) continue; - LIST_REMOVE(mon, listEntry); UA_MonitoredItem_delete(server, mon); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_GOOD; } - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADMONITOREDITEMIDINVALID; } #endif /* UA_ENABLE_SUBSCRIPTIONS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_securechannel.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_securechannel.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -38364,7 +41749,7 @@ removeSecureChannel(UA_Server *server, channel_entry *entry, TAILQ_REMOVE(&server->channels, entry, pointers); /* Update the statistics */ - UA_SecureChannelStatistics *scs = &server->serverStats.scs; + UA_SecureChannelStatistics *scs = &server->secureChannelStatistics; UA_atomic_subSize(&scs->currentChannelCount, 1); switch(event) { case UA_DIAGNOSTICEVENT_CLOSE: @@ -38392,7 +41777,9 @@ removeSecureChannel(UA_Server *server, channel_entry *entry, entry->cleanupCallback.callback = (UA_ApplicationCallback)removeSecureChannelCallback; entry->cleanupCallback.application = NULL; entry->cleanupCallback.data = entry; - UA_WorkQueue_enqueueDelayed(&server->workQueue, &entry->cleanupCallback); + entry->cleanupCallback.nextTime = UA_DateTime_nowMonotonic() + 1; + entry->cleanupCallback.interval = 0; /* Remove the structure */ + UA_Timer_addTimerEntry(&server->timer, &entry->cleanupCallback, NULL); } void @@ -38415,6 +41802,12 @@ UA_Server_cleanupTimedOutSecureChannels(UA_Server *server, continue; } + /* Is the SecurityToken already created? */ + if(entry->channel.securityToken.createdAt == 0) { + /* No -> channel is still in progress of being opened, do not remove */ + continue; + } + /* Has the SecurityToken timed out? */ UA_DateTime timeout = entry->channel.securityToken.createdAt + @@ -38473,13 +41866,11 @@ UA_Server_createSecureChannel(UA_Server *server, UA_Connection *connection) { /* Check if there exists a free SC, otherwise try to purge one SC without a * session the purge has been introduced to pass CTT, it is not clear what * strategy is expected here */ - if(server->serverStats.scs.currentChannelCount >= server->config.maxSecureChannels && + if((server->secureChannelStatistics.currentChannelCount >= + server->config.maxSecureChannels) && !purgeFirstChannelWithoutSession(server)) return UA_STATUSCODE_BADOUTOFMEMORY; - UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SECURECHANNEL, - "Creating a new SecureChannel"); - channel_entry *entry = (channel_entry *)UA_malloc(sizeof(channel_entry)); if(!entry) return UA_STATUSCODE_BADOUTOFMEMORY; @@ -38488,22 +41879,22 @@ UA_Server_createSecureChannel(UA_Server *server, UA_Connection *connection) { /* TODO: Use the connection config from the correct network layer */ UA_SecureChannel_init(&entry->channel, &server->config.networkLayers[0].localConnectionConfig); - entry->channel.securityToken.channelId = 0; - entry->channel.securityToken.createdAt = UA_DateTime_nowMonotonic(); - entry->channel.securityToken.revisedLifetime = server->config.maxSecurityTokenLifetime; + entry->channel.certificateVerification = &server->config.certificateVerification; + entry->channel.processOPNHeader = UA_Server_configSecureChannel; TAILQ_INSERT_TAIL(&server->channels, entry, pointers); UA_Connection_attachSecureChannel(connection, &entry->channel); - UA_atomic_addSize(&server->serverStats.scs.currentChannelCount, 1); - UA_atomic_addSize(&server->serverStats.scs.cumulatedChannelCount, 1); + server->secureChannelStatistics.currentChannelCount++; + server->secureChannelStatistics.cumulatedChannelCount++; return UA_STATUSCODE_GOOD; } UA_StatusCode -UA_Server_configSecureChannel(UA_Server *server, UA_SecureChannel *channel, +UA_Server_configSecureChannel(void *application, UA_SecureChannel *channel, const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) { /* Iterate over available endpoints and choose the correct one */ UA_SecurityPolicy *securityPolicy = NULL; + UA_Server *const server = (UA_Server *const) application; for(size_t i = 0; i < server->config.securityPoliciesSize; ++i) { UA_SecurityPolicy *policy = &server->config.securityPolicies[i]; if(!UA_ByteString_equal(&asymHeader->securityPolicyUri, &policy->policyUri)) @@ -38540,7 +41931,7 @@ static UA_StatusCode UA_SecureChannelManager_open(UA_Server *server, UA_SecureChannel *channel, const UA_OpenSecureChannelRequest *request, UA_OpenSecureChannelResponse *response) { - if(channel->state != UA_SECURECHANNELSTATE_CLOSED) { + if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT) { UA_LOG_ERROR_CHANNEL(&server->config.logger, channel, "Called open on already open or closed channel"); return UA_STATUSCODE_BADINTERNALERROR; @@ -38576,7 +41967,7 @@ UA_SecureChannelManager_open(UA_Server *server, UA_SecureChannel *channel, * first symmetric messages is received. */ response->securityToken = channel->securityToken; response->securityToken.createdAt = UA_DateTime_now(); /* Only for sending */ - response->responseHeader.timestamp = UA_DateTime_now(); + response->responseHeader.timestamp = response->securityToken.createdAt; response->responseHeader.requestHandle = request->requestHeader.requestHandle; retval = UA_ByteString_copy(&channel->localNonce, &response->serverNonce); if(retval != UA_STATUSCODE_GOOD) @@ -38660,8 +42051,9 @@ Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel *channel, /* Logging */ if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) { - UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, - "SecureChannel renewed"); + UA_Float lifetime = (UA_Float)response->securityToken.revisedLifetime / 1000; + UA_LOG_INFO_CHANNEL(&server->config.logger, channel, "SecureChannel renewed " + "with a revised lifetime of %.2fs", lifetime); } else { UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, "Renewing SecureChannel failed"); @@ -38681,8 +42073,12 @@ Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel *channel, /* Logging */ if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) { + UA_Float lifetime = (UA_Float)response->securityToken.revisedLifetime / 1000; UA_LOG_INFO_CHANNEL(&server->config.logger, channel, - "Opened SecureChannel"); + "SecureChannel opened with SecurityPolicy %.*s " + "and a revised lifetime of %.2fs", + (int)channel->securityPolicy->policyUri.length, + channel->securityPolicy->policyUri.data, lifetime); } else { UA_LOG_INFO_CHANNEL(&server->config.logger, channel, "Opening a SecureChannel failed"); @@ -38697,7 +42093,7 @@ Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) { UA_DIAGNOSTICEVENT_CLOSE); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_nodemanagement.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_nodemanagement.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -38714,10 +42110,17 @@ Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) { * Copyright 2017 (c) frax2222 * Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH * Copyright 2017 (c) Christian von Arnim + * Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) * Copyright 2017 (c) Henrik Norrman + * Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner) */ +static UA_StatusCode +setMethodNode_callback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback methodCallback); + /*********************/ /* Edit Node Context */ /*********************/ @@ -38725,55 +42128,65 @@ Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) { UA_StatusCode UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId, void **nodeContext) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = getNodeContext(server, nodeId, nodeContext); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } UA_StatusCode getNodeContext(UA_Server *server, UA_NodeId nodeId, - void **nodeContext) { + void **nodeContext) { const UA_Node *node = UA_NODESTORE_GET(server, &nodeId); if(!node) return UA_STATUSCODE_BADNODEIDUNKNOWN; - *nodeContext = node->context; + *nodeContext = node->head.context; UA_NODESTORE_RELEASE(server, node); return UA_STATUSCODE_GOOD; } static UA_StatusCode setDeconstructedNode(UA_Server *server, UA_Session *session, - UA_Node *node, void *context) { - node->constructed = false; + UA_NodeHead *head, void *context) { + head->constructed = false; return UA_STATUSCODE_GOOD; } static UA_StatusCode setConstructedNodeContext(UA_Server *server, UA_Session *session, - UA_Node *node, void *context) { - node->context = context; - node->constructed = true; + UA_NodeHead *head, void *context) { + head->context = context; + head->constructed = true; return UA_STATUSCODE_GOOD; } static UA_StatusCode editNodeContext(UA_Server *server, UA_Session* session, - UA_Node* node, void *context) { - node->context = context; + UA_NodeHead *head, void *context) { + head->context = context; return UA_STATUSCODE_GOOD; } UA_StatusCode +setNodeContext(UA_Server *server, UA_NodeId nodeId, + void *nodeContext) { + return UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback)editNodeContext, nodeContext); +} + +UA_StatusCode UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId, void *nodeContext) { - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId, - (UA_EditNodeCallback)editNodeContext, nodeContext); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = setNodeContext(server, nodeId, nodeContext); + UA_UNLOCK(&server->serviceMutex); return retval; } +static UA_StatusCode +checkSetIsDynamicVariable(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId); + /**********************/ /* Consistency Checks */ /**********************/ @@ -38785,85 +42198,92 @@ const UA_NodeId parentReferences[UA_PARENT_REFERENCES_COUNT] = { {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}} }; +static void +logAddNode(const UA_Logger *logger, UA_Session *session, + const UA_NodeId *nodeId, const char *msg) { + UA_LOG_NODEID_INFO(nodeId, + UA_LOG_INFO_SESSION(logger, session, "AddNode (%.*s): %s", + (int)nodeIdStr.length, nodeIdStr.data, msg)); +} + /* Check if the requested parent node exists, has the right node class and is * referenced with an allowed (hierarchical) reference type. For "type" nodes, * only hasSubType references are allowed. */ static UA_StatusCode -checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeClass, +checkParentReference(UA_Server *server, UA_Session *session, const UA_NodeHead *head, const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) { - /* Objects do not need a parent (e.g. mandatory/optional modellingrules) */ - /* Also, there are some variables which do not have parents, e.g. EnumStrings, EnumValues */ - if((nodeClass == UA_NODECLASS_OBJECT || nodeClass == UA_NODECLASS_VARIABLE) && + /* Objects do not need a parent (e.g. mandatory/optional modellingrules). + * Also, there are some variables which do not have parents, e.g. + * EnumStrings, EnumValues */ + if((head->nodeClass == UA_NODECLASS_OBJECT || + head->nodeClass == UA_NODECLASS_VARIABLE) && UA_NodeId_isNull(parentNodeId) && UA_NodeId_isNull(referenceTypeId)) return UA_STATUSCODE_GOOD; /* See if the parent exists */ const UA_Node *parent = UA_NODESTORE_GET(server, parentNodeId); if(!parent) { - UA_LOG_NODEID_WRAP(parentNodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Parent node %.*s not found", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, &head->nodeId, + "Parent node not found"); return UA_STATUSCODE_BADPARENTNODEIDINVALID; } - UA_NodeClass parentNodeClass = parent->nodeClass; + UA_NodeClass parentNodeClass = parent->head.nodeClass; UA_NODESTORE_RELEASE(server, parent); /* Check the referencetype exists */ - const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode*) - UA_NODESTORE_GET(server, referenceTypeId); + const UA_Node *referenceType = UA_NODESTORE_GET(server, referenceTypeId); if(!referenceType) { - UA_LOG_NODEID_WRAP(referenceTypeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Reference type %.*s to the parent not found", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, &head->nodeId, + "Reference type to the parent not found"); return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; } /* Check if the referencetype is a reference type node */ - if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) { - UA_LOG_NODEID_WRAP(referenceTypeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Reference type %.*s to the parent is not a ReferenceTypeNode", - (int)nodeIdStr.length, nodeIdStr.data)); - UA_NODESTORE_RELEASE(server, (const UA_Node*)referenceType); + if(referenceType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) { + logAddNode(&server->config.logger, session, &head->nodeId, + "Reference type to the parent is not a ReferenceTypeNode"); + UA_NODESTORE_RELEASE(server, referenceType); return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; } - UA_Boolean referenceTypeIsAbstract = referenceType->isAbstract; - UA_NODESTORE_RELEASE(server, (const UA_Node*)referenceType); /* Check that the reference type is not abstract */ + UA_Boolean referenceTypeIsAbstract = referenceType->referenceTypeNode.isAbstract; + UA_NODESTORE_RELEASE(server, referenceType); if(referenceTypeIsAbstract == true) { - UA_LOG_NODEID_WRAP(referenceTypeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Abstract reference type %.*s to the parent not allowed", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, &head->nodeId, + "Abstract reference type to the parent not allowed"); return UA_STATUSCODE_BADREFERENCENOTALLOWED; } /* Check hassubtype relation for type nodes */ - if(nodeClass == UA_NODECLASS_DATATYPE || - nodeClass == UA_NODECLASS_VARIABLETYPE || - nodeClass == UA_NODECLASS_OBJECTTYPE || - nodeClass == UA_NODECLASS_REFERENCETYPE) { - /* type needs hassubtype reference to the supertype */ - if(!UA_NodeId_equal(referenceTypeId, &subtypeId)) { - UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Type nodes need to have a HasSubType " - "reference to the parent"); + if(head->nodeClass == UA_NODECLASS_DATATYPE || + head->nodeClass == UA_NODECLASS_VARIABLETYPE || + head->nodeClass == UA_NODECLASS_OBJECTTYPE || + head->nodeClass == UA_NODECLASS_REFERENCETYPE) { + /* Type needs hassubtype reference to the supertype */ + if(referenceType->referenceTypeNode.referenceTypeIndex != + UA_REFERENCETYPEINDEX_HASSUBTYPE) { + logAddNode(&server->config.logger, session, &head->nodeId, + "Type nodes need to have a HasSubType reference to the parent"); return UA_STATUSCODE_BADREFERENCENOTALLOWED; } - /* supertype needs to be of the same node type */ - if(parentNodeClass != nodeClass) { - UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Type nodes needs to be of the same node " - "type as their parent"); + /* Supertype needs to be of the same node type */ + if(parentNodeClass != head->nodeClass) { + logAddNode(&server->config.logger, session, &head->nodeId, + "Type nodes needs to be of the same node " + "type as their parent"); return UA_STATUSCODE_BADPARENTNODEIDINVALID; } return UA_STATUSCODE_GOOD; } /* Test if the referencetype is hierarchical */ - if(!isNodeInTree(server, referenceTypeId, &hierarchicalReferences, &subtypeId, 1)) { - UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Reference type to the parent is not hierarchical"); + const UA_NodeId hierarchRefs = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); + if(!isNodeInTree_singleRef(server, referenceTypeId, &hierarchRefs, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) { + logAddNode(&server->config.logger, session, &head->nodeId, + "Reference type to the parent is not hierarchical"); return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; } @@ -38871,81 +42291,193 @@ checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeCl } static UA_StatusCode +setDefaultValue(UA_Server *server, const UA_VariableNode *node) { + /* Get the DataType */ + UA_StatusCode res = UA_STATUSCODE_GOOD; + const UA_DataType *type = UA_Server_findDataType(server, &node->dataType); + if(!type) { + /* No description for the DataType found. It is possible that an + * abstract DataType is used, e.g. UInteger. Browse to see if there is a + * non-abstract subtype that can be used for the default value. + * + * Look up and downwards in the hierarchy. Some data types (e.g. + * UtcTime) are derived from a non-abstract data type. This is then used + * for the actual value, Use the first match. */ + UA_ReferenceTypeSet refs = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); + UA_ExpandedNodeId *typeCandidates = NULL; + size_t typeCandidatesSize = 0; + res = browseRecursive(server, 1, &node->dataType, + UA_BROWSEDIRECTION_BOTH, &refs, + UA_NODECLASS_DATATYPE, false, + &typeCandidatesSize, &typeCandidates); + if(res != UA_STATUSCODE_GOOD) + return res; + + for(size_t i = 0; i < typeCandidatesSize; i++) { + /* Skip BaseDataType (Variant). This is the root of the DataType + * hierarchy. Variables of BaseDataType can be empty. */ + if(UA_NodeId_equal(&UA_TYPES[UA_TYPES_VARIANT].typeId, + &typeCandidates[i].nodeId)) + continue; + type = UA_Server_findDataType(server, &typeCandidates[i].nodeId); + if(type) + break; + } + + UA_Array_delete(typeCandidates, typeCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + if(!type) + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + /* Set up the value with the default content */ + UA_Variant val; + UA_Variant_init(&val); + if(node->valueRank < 0) { + /* Set a scalar */ + void *data = UA_new(type); + if(!data) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_Variant_setScalar(&val, data, type); + } else if(node->valueRank == 0) { + /* Use an empty array of one dimension */ + UA_Variant_setArray(&val, NULL, 0, type); + } else { + /* Write an array that matches the ArrayDimensions */ + res = UA_Array_copy(node->arrayDimensions, node->arrayDimensionsSize, + (void**)&val.arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]); + if(res != UA_STATUSCODE_GOOD) + return res; + val.arrayDimensionsSize = node->arrayDimensionsSize; + + /* No length restriction in the ArrayDimension -> use length 1 */ + size_t size = 1; + for(size_t i = 0; i < val.arrayDimensionsSize; i++) { + if(val.arrayDimensions[i] == 0) + val.arrayDimensions[i] = 1; + size *= val.arrayDimensions[i]; + } + + /* Create the content array */ + void *data = UA_Array_new(size, type); + if(!data) { + UA_Variant_clear(&val); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + val.data = data; + val.arrayLength = size; + val.type = type; + } + + /* Write the value */ + res = writeAttribute(server, &server->adminSession, &node->head.nodeId, + UA_ATTRIBUTEID_VALUE, &val, &UA_TYPES[UA_TYPES_VARIANT]); + + /* Clean up */ + UA_Variant_clear(&val); + return res; +} + +static UA_StatusCode typeCheckVariableNode(UA_Server *server, UA_Session *session, const UA_VariableNode *node, const UA_VariableTypeNode *vt) { - /* The value might come from a datasource, so we perform a - * regular read. */ - UA_DataValue value; - UA_DataValue_init(&value); - UA_StatusCode retval = readValueAttribute(server, session, node, &value); - if(retval != UA_STATUSCODE_GOOD) - return retval; - - UA_NodeId baseDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE); - /* Check the datatype against the vt */ - /* If the node does not have any value and the dataType is BaseDataType, - * then it's also fine. This is the default for empty nodes. */ - if(!compatibleDataType(server, &node->dataType, &vt->dataType, false) && - (value.hasValue || !UA_NodeId_equal(&node->dataType, &baseDataType))) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The value of %.*s is incompatible with " - "the datatype of the VariableType", - (int)nodeIdStr.length, nodeIdStr.data)); - UA_DataValue_clear(&value); + if(!compatibleDataTypes(server, &node->dataType, &vt->dataType)) { + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The value of is incompatible with " + "the datatype of the VariableType"); return UA_STATUSCODE_BADTYPEMISMATCH; } /* Check valueRank against array dimensions */ if(!compatibleValueRankArrayDimensions(server, session, node->valueRank, node->arrayDimensionsSize)) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The value rank of %.*s is incompatible " - "with its array dimensions", (int)nodeIdStr.length, nodeIdStr.data)); - UA_DataValue_clear(&value); + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The value rank of is incompatible with its array dimensions"); return UA_STATUSCODE_BADTYPEMISMATCH; } /* Check valueRank against the vt */ if(!compatibleValueRanks(node->valueRank, vt->valueRank)) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The value rank of %.*s is incompatible " - "with the value rank of the VariableType", - (int)nodeIdStr.length, nodeIdStr.data)); - UA_DataValue_clear(&value); + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The value rank is incompatible " + "with the value rank of the VariableType"); return UA_STATUSCODE_BADTYPEMISMATCH; } /* Check array dimensions against the vt */ if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions, node->arrayDimensionsSize, node->arrayDimensions)) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The array dimensions of %.*s are " - "incompatible with the array dimensions of the VariableType", - (int)nodeIdStr.length, nodeIdStr.data)); - UA_DataValue_clear(&value); + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The array dimensions are incompatible with the " + "array dimensions of the VariableType"); return UA_STATUSCODE_BADTYPEMISMATCH; } /* Typecheck the value */ - if(value.hasValue && value.value.data) { - /* If the type-check failed write the same value again. The - * write-service tries to convert to the correct type... */ - if(!compatibleValue(server, session, &node->dataType, node->valueRank, - node->arrayDimensionsSize, node->arrayDimensions, - &value.value, NULL)) { - retval = writeWithWriteValue(server, &node->nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value.value); + + /* The value might come from a datasource, so we perform a + * regular read. */ + UA_DataValue value; + UA_DataValue_init(&value); + UA_StatusCode retval = readValueAttribute(server, session, node, &value); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Only BaseDataType (Variant) can have empty values. Create default content + * otherwise that matches the constraints. */ + if(!value.hasValue || !value.value.type) { + if(!UA_NodeId_equal(&node->dataType, &UA_TYPES[UA_TYPES_VARIANT].typeId)) { + /* Warn if that is configured */ + if(!server->bootstrapNS0 && + server->config.allowEmptyVariables != UA_RULEHANDLING_ACCEPT) + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The value is empty. But this is only allowed for BaseDataType. " + "Create a matching default value."); + + /* Abort if that is configured */ + if(server->config.allowEmptyVariables == UA_RULEHANDLING_ABORT) + retval = UA_STATUSCODE_BADTYPEMISMATCH; + + /* Try to generate a default value if that is configured */ + if(server->config.allowEmptyVariables == UA_RULEHANDLING_DEFAULT) { + retval = setDefaultValue(server, node); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Could not create a default value " + "with StatusCode %s", (int)nodeIdStr.length, + nodeIdStr.data, UA_StatusCode_name(retval))); + } + + /* Reread the current value for compat tests below */ + UA_DataValue_clear(&value); + retval = readValueAttribute(server, session, node, &value); + } } - UA_DataValue_clear(&value); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The value of %.*s is incompatible with the " - "variable definition", (int)nodeIdStr.length, nodeIdStr.data)); + UA_DataValue_clear(&value); + return retval; + } + } + + /* Perform the value typecheck. If this fails, write the current value + * again. The write-service tries to convert to the correct type... */ + const char *reason; + if(!compatibleValue(server, session, &node->dataType, node->valueRank, + node->arrayDimensionsSize, node->arrayDimensions, + &value.value, NULL, &reason)) { + retval = writeValueAttribute(server, session, &node->head.nodeId, &value.value); + if(retval != UA_STATUSCODE_GOOD) { + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The value is incompatible with the variable definition"); } } + UA_DataValue_clear(&value); return retval; } @@ -38964,84 +42496,62 @@ static const UA_NodeId hasTypeDefinition = * changes were made. */ static UA_StatusCode useVariableTypeAttributes(UA_Server *server, UA_Session *session, - const UA_VariableNode **node_ptr, + const UA_VariableNode *node, const UA_VariableTypeNode *vt) { - const UA_VariableNode *node = *node_ptr; - UA_Boolean modified = false; - /* If no value is set, see if the vt provides one and copy it. This needs to * be done before copying the datatype from the vt, as setting the datatype * triggers a typecheck. */ - UA_DataValue orig; - UA_DataValue_init(&orig); - UA_StatusCode retval = readValueAttribute(server, session, node, &orig); + UA_Variant orig; + UA_StatusCode retval = + readWithReadValue(server, &node->head.nodeId, UA_ATTRIBUTEID_VALUE, &orig); if(retval != UA_STATUSCODE_GOOD) return retval; - if(orig.value.type) { + if(orig.type) { /* A value is present */ - UA_DataValue_clear(&orig); + UA_Variant_clear(&orig); } else { - UA_WriteValue v; - UA_WriteValue_init(&v); - retval = readValueAttribute(server, session, (const UA_VariableNode*)vt, &v.value); - if(retval == UA_STATUSCODE_GOOD && v.value.hasValue) { - v.nodeId = node->nodeId; - v.attributeId = UA_ATTRIBUTEID_VALUE; - retval = writeWithSession(server, session, &v); - modified = true; - } - UA_DataValue_clear(&v.value); - if(retval != UA_STATUSCODE_GOOD) - return retval; + UA_DataValue v; + UA_DataValue_init(&v); + retval = readValueAttribute(server, session, (const UA_VariableNode*)vt, &v); + if(retval == UA_STATUSCODE_GOOD && v.hasValue) { + retval = writeValueAttribute(server, session, &node->head.nodeId, &v.value); + } + UA_DataValue_clear(&v); + + if(retval != UA_STATUSCODE_GOOD) { + logAddNode(&server->config.logger, session, &node->head.nodeId, + "The default content of the VariableType could " + "not be used. This may happen if the VariableNode " + "makes additional restrictions."); + retval = UA_STATUSCODE_GOOD; + } } /* If no datatype is given, use the datatype of the vt */ if(UA_NodeId_isNull(&node->dataType)) { - UA_LOG_INFO_SESSION(&server->config.logger, session, "AddNodes: " - "No datatype given; Copy the datatype attribute " - "from the TypeDefinition"); - UA_WriteValue v; - UA_WriteValue_init(&v); - v.nodeId = node->nodeId; - v.attributeId = UA_ATTRIBUTEID_DATATYPE; - v.value.hasValue = true; - UA_Variant_setScalar(&v.value.value, (void*)(uintptr_t)&vt->dataType, - &UA_TYPES[UA_TYPES_NODEID]); - retval = writeWithSession(server, session, &v); - modified = true; + logAddNode(&server->config.logger, session, &node->head.nodeId, + "No datatype given; Copy the datatype attribute " + "from the TypeDefinition"); + retval = writeAttribute(server, session, &node->head.nodeId, + UA_ATTRIBUTEID_DATATYPE, &vt->dataType, + &UA_TYPES[UA_TYPES_NODEID]); if(retval != UA_STATUSCODE_GOOD) return retval; } /* Use the ArrayDimensions of the vt */ if(node->arrayDimensionsSize == 0 && vt->arrayDimensionsSize > 0) { - UA_WriteValue v; - UA_WriteValue_init(&v); - v.nodeId = node->nodeId; - v.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS; - v.value.hasValue = true; - UA_Variant_setArray(&v.value.value, vt->arrayDimensions, - vt->arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); - retval = writeWithSession(server, session, &v); - modified = true; - if(retval != UA_STATUSCODE_GOOD) - return retval; - } - - /* If the node was modified, update the pointer to the new version */ - if(modified) { - const UA_VariableNode *updated = (const UA_VariableNode*) - UA_NODESTORE_GET(server, &node->nodeId); - - if(!updated) - return UA_STATUSCODE_BADINTERNALERROR; - - UA_NODESTORE_RELEASE(server, (const UA_Node*)node); - *node_ptr = updated; + UA_Variant v; + UA_Variant_init(&v); + UA_Variant_setArray(&v, vt->arrayDimensions, vt->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_UINT32]); + retval = writeAttribute(server, session, &node->head.nodeId, + UA_ATTRIBUTEID_ARRAYDIMENSIONS, &v, + &UA_TYPES[UA_TYPES_VARIANT]); } - return UA_STATUSCODE_GOOD; + return retval; } /* Search for an instance of "browseName" in node searchInstance. Used during @@ -39084,8 +42594,6 @@ findChildByBrowsename(UA_Server *server, UA_Session *session, static const UA_NodeId mandatoryId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_MODELLINGRULE_MANDATORY}}; -static const UA_NodeId hasModellingRuleId = - {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASMODELLINGRULE}}; static UA_Boolean isMandatoryChild(UA_Server *server, UA_Session *session, @@ -39096,14 +42604,17 @@ isMandatoryChild(UA_Server *server, UA_Session *session, return false; /* Look for the reference making the child mandatory */ - for(size_t i = 0; i < child->referencesSize; ++i) { - UA_NodeReferenceKind *refs = &child->references[i]; - if(!UA_NodeId_equal(&hasModellingRuleId, &refs->referenceTypeId)) + UA_NodePointer mandatoryP = UA_NodePointer_fromNodeId(&mandatoryId); + for(size_t i = 0; i < child->head.referencesSize; ++i) { + UA_NodeReferenceKind *rk = &child->head.references[i]; + if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASMODELLINGRULE) continue; - if(refs->isInverse) + if(rk->isInverse) continue; - for(size_t j = 0; j < refs->refTargetsSize; ++j) { - if(UA_NodeId_equal(&mandatoryId, &refs->refTargets[j].targetId.nodeId)) { + + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + if(UA_NodePointer_equal(mandatoryP, t->targetId)) { UA_NODESTORE_RELEASE(server, child); return true; } @@ -39118,17 +42629,68 @@ static UA_StatusCode copyAllChildren(UA_Server *server, UA_Session *session, const UA_NodeId *source, const UA_NodeId *destination); -static UA_StatusCode -recursiveTypeCheckAddChildren(UA_Server *server, UA_Session *session, - const UA_Node **node, const UA_Node *type); - static void Operation_addReference(UA_Server *server, UA_Session *session, void *context, const UA_AddReferencesItem *item, UA_StatusCode *retval); +UA_StatusCode +addRef(UA_Server *server, UA_Session *session, const UA_NodeId *sourceId, + const UA_NodeId *referenceTypeId, const UA_NodeId *targetId, + UA_Boolean forward) { + UA_AddReferencesItem ref_item; + UA_AddReferencesItem_init(&ref_item); + ref_item.sourceNodeId = *sourceId; + ref_item.referenceTypeId = *referenceTypeId; + ref_item.isForward = forward; + ref_item.targetNodeId.nodeId = *targetId; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + Operation_addReference(server, session, NULL, &ref_item, &retval); + return retval; +} + static UA_StatusCode -copyChild(UA_Server *server, UA_Session *session, const UA_NodeId *destinationNodeId, +addInterfaceChildren(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, const UA_NodeId *typeId) { + /* Get the hierarchy of the type and all its supertypes */ + UA_NodeId *hierarchy = NULL; + size_t hierarchySize = 0; + UA_StatusCode retval = getAllInterfaceChildNodeIds(server, nodeId, typeId, + &hierarchy, &hierarchySize); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Copy members of the type and supertypes (and instantiate them) */ + for(size_t i = 0; i < hierarchySize; ++i) { + retval = copyAllChildren(server, session, &hierarchy[i], nodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]); + return retval; + } + } + + for(size_t i = 0; i < hierarchySize; ++i) { + UA_NodeId refId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASINTERFACE); + retval = addRef(server, &server->adminSession, nodeId, &refId, &hierarchy[i], true); + + /* Don't add the original HasInterface reference to ObjectType sub nodes */ + if(retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) { + retval = UA_STATUSCODE_GOOD; + } else if(retval != UA_STATUSCODE_GOOD) { + break; + } + } + + UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]); + return retval; +} + +static UA_StatusCode +copyChild(UA_Server *server, UA_Session *session, + const UA_NodeId *destinationNodeId, const UA_ReferenceDescription *rd) { + UA_assert(session); + /* Is there an existing child with the browsename? */ UA_NodeId existingChild = UA_NODEID_NULL; UA_StatusCode retval = findChildByBrowsename(server, session, destinationNodeId, @@ -39150,18 +42712,13 @@ copyChild(UA_Server *server, UA_Session *session, const UA_NodeId *destinationNo if(!isMandatoryChild(server, session, &rd->nodeId.nodeId)) { if(!server->config.nodeLifecycle.createOptionalChild) return UA_STATUSCODE_GOOD; - - UA_UNLOCK(server->serviceMutex); - retval = server->config.nodeLifecycle.createOptionalChild(server, - &session->sessionId, - session->sessionHandle, - &rd->nodeId.nodeId, - destinationNodeId, - &rd->referenceTypeId); - UA_LOCK(server->serviceMutex); - if(retval == UA_FALSE) { + UA_UNLOCK(&server->serviceMutex); + UA_Boolean createChild = server->config.nodeLifecycle. + createOptionalChild(server, &session->sessionId, session->sessionHandle, + &rd->nodeId.nodeId, destinationNodeId, &rd->referenceTypeId); + UA_LOCK(&server->serviceMutex); + if(!createChild) return UA_STATUSCODE_GOOD; - } } /* Child is a method -> create a reference */ @@ -39187,40 +42744,54 @@ copyChild(UA_Server *server, UA_Session *session, const UA_NodeId *destinationNo return retval; /* Remove the context of the copied node */ - node->context = NULL; - node->constructed = false; + node->head.context = NULL; + node->head.constructed = false; +#ifdef UA_ENABLE_SUBSCRIPTIONS + node->head.monitoredItems = NULL; +#endif /* Reset the NodeId (random numeric id will be assigned in the nodestore) */ - UA_NodeId_clear(&node->nodeId); - node->nodeId.namespaceIndex = destinationNodeId->namespaceIndex; - - if (server->config.nodeLifecycle.generateChildNodeId) { - UA_UNLOCK(server->serviceMutex); - retval = server->config.nodeLifecycle.generateChildNodeId(server, - &session->sessionId, session->sessionHandle, - &rd->nodeId.nodeId, - destinationNodeId, - &rd->referenceTypeId, - &node->nodeId); - UA_LOCK(server->serviceMutex); + UA_NodeId_clear(&node->head.nodeId); + node->head.nodeId.namespaceIndex = destinationNodeId->namespaceIndex; + + if(server->config.nodeLifecycle.generateChildNodeId) { + UA_UNLOCK(&server->serviceMutex); + retval = server->config.nodeLifecycle. + generateChildNodeId(server, &session->sessionId, session->sessionHandle, + &rd->nodeId.nodeId, destinationNodeId, + &rd->referenceTypeId, &node->head.nodeId); + UA_LOCK(&server->serviceMutex); if(retval != UA_STATUSCODE_GOOD) { UA_NODESTORE_DELETE(server, node); return retval; } } - /* Remove references, they are re-created from scratch in addnode_finish */ /* TODO: Be more clever in removing references that are re-added during * addnode_finish. That way, we can call addnode_finish also on children that were * manually added by the user during addnode_begin and addnode_finish. */ /* For now we keep all the modelling rule references and delete all others */ - UA_NodeId modellingRuleReferenceId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE); - UA_Node_deleteReferencesSubset(node, 1, &modellingRuleReferenceId); + const UA_NodeId nodeId_typesFolder= UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER); + const UA_ReferenceTypeSet reftypes_aggregates = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_AGGREGATES); + UA_ReferenceTypeSet reftypes_skipped; + /* Check if the hasModellingRule-reference is required (configured or node in an + instance declaration) */ + if(server->config.modellingRulesOnInstances || + isNodeInTree(server, destinationNodeId, + &nodeId_typesFolder, &reftypes_aggregates)) { + reftypes_skipped = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASMODELLINGRULE); + } else { + UA_ReferenceTypeSet_init(&reftypes_skipped); + } + reftypes_skipped = UA_ReferenceTypeSet_union(reftypes_skipped, UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE)); + UA_Node_deleteReferencesSubset(node, &reftypes_skipped); /* Add the node to the nodestore */ UA_NodeId newNodeId; retval = UA_NODESTORE_INSERT(server, node, &newNodeId); + /* node = NULL; The pointer is no longer valid */ if(retval != UA_STATUSCODE_GOOD) return retval; @@ -39229,13 +42800,39 @@ copyChild(UA_Server *server, UA_Session *session, const UA_NodeId *destinationNo &rd->referenceTypeId, &rd->typeDefinition.nodeId); if(retval != UA_STATUSCODE_GOOD) { UA_NODESTORE_REMOVE(server, &newNodeId); + UA_NodeId_clear(&newNodeId); return retval; } + if (rd->nodeClass == UA_NODECLASS_VARIABLE) { + retval = checkSetIsDynamicVariable(server, session, &newNodeId); + + if(retval != UA_STATUSCODE_GOOD) { + UA_NODESTORE_REMOVE(server, &newNodeId); + return retval; + } + } + /* For the new child, recursively copy the members of the original. No * typechecking is performed here. Assuming that the original is * consistent. */ retval = copyAllChildren(server, session, &rd->nodeId.nodeId, &newNodeId); + if(retval != UA_STATUSCODE_GOOD) { + deleteNode(server, newNodeId, true); + return retval; + } + + /* Check if its a dynamic variable, add all type and/or interface + * children and call the constructor */ + retval = AddNode_finish(server, session, &newNodeId); + if(retval != UA_STATUSCODE_GOOD) { + deleteNode(server, newNodeId, true); + return retval; + } + + /* Clean up. Because it can happen that a string is assigned as ID at + * generateChildNodeId. */ + UA_NodeId_clear(&newNodeId); } return retval; @@ -39268,7 +42865,7 @@ copyAllChildren(UA_Server *server, UA_Session *session, UA_ReferenceDescription *rd = &br.references[i]; retval = copyChild(server, session, destination, rd); if(retval != UA_STATUSCODE_GOOD) - return retval; + break; } UA_BrowseResult_clear(&br); @@ -39277,11 +42874,11 @@ copyAllChildren(UA_Server *server, UA_Session *session, static UA_StatusCode addTypeChildren(UA_Server *server, UA_Session *session, - const UA_Node *node, const UA_Node *type) { + const UA_NodeId *nodeId, const UA_NodeId *typeId) { /* Get the hierarchy of the type and all its supertypes */ UA_NodeId *hierarchy = NULL; size_t hierarchySize = 0; - UA_StatusCode retval = getParentTypeAndInterfaceHierarchy(server, &type->nodeId, + UA_StatusCode retval = getParentTypeAndInterfaceHierarchy(server, typeId, &hierarchy, &hierarchySize); if(retval != UA_STATUSCODE_GOOD) return retval; @@ -39289,7 +42886,7 @@ addTypeChildren(UA_Server *server, UA_Session *session, /* Copy members of the type and supertypes (and instantiate them) */ for(size_t i = 0; i < hierarchySize; ++i) { - retval = copyAllChildren(server, session, &hierarchy[i], &node->nodeId); + retval = copyAllChildren(server, session, &hierarchy[i], nodeId); if(retval != UA_STATUSCODE_GOOD) break; } @@ -39298,22 +42895,6 @@ addTypeChildren(UA_Server *server, UA_Session *session, return retval; } -static UA_StatusCode -addRef(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, - const UA_NodeId *referenceTypeId, const UA_NodeId *parentNodeId, - UA_Boolean forward) { - UA_AddReferencesItem ref_item; - UA_AddReferencesItem_init(&ref_item); - ref_item.sourceNodeId = *nodeId; - ref_item.referenceTypeId = *referenceTypeId; - ref_item.isForward = forward; - ref_item.targetNodeId.nodeId = *parentNodeId; - - UA_StatusCode retval = UA_STATUSCODE_GOOD; - Operation_addReference(server, session, NULL, &ref_item, &retval); - return retval; -} - /************/ /* Add Node */ /************/ @@ -39331,15 +42912,16 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, return UA_STATUSCODE_BADNODEIDUNKNOWN; /* Use the typeDefinition as parent for type-nodes */ - if(node->nodeClass == UA_NODECLASS_VARIABLETYPE || - node->nodeClass == UA_NODECLASS_OBJECTTYPE || - node->nodeClass == UA_NODECLASS_REFERENCETYPE || - node->nodeClass == UA_NODECLASS_DATATYPE) { + const UA_NodeHead *head = &node->head; + if(head->nodeClass == UA_NODECLASS_VARIABLETYPE || + head->nodeClass == UA_NODECLASS_OBJECTTYPE || + head->nodeClass == UA_NODECLASS_REFERENCETYPE || + head->nodeClass == UA_NODECLASS_DATATYPE) { if(UA_NodeId_equal(referenceTypeId, &UA_NODEID_NULL)) referenceTypeId = &hasSubtype; const UA_Node *parentNode = UA_NODESTORE_GET(server, parentNodeId); if(parentNode) { - if(parentNode->nodeClass == node->nodeClass) + if(parentNode->head.nodeClass == head->nodeClass) typeDefinitionId = parentNodeId; UA_NODESTORE_RELEASE(server, parentNode); } @@ -39347,37 +42929,30 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, UA_StatusCode retval; /* Make sure newly created node does not have itself as parent */ - if (UA_NodeId_equal(nodeId, parentNodeId)) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The node %.*s can not have " - "itself as parent", - (int)nodeIdStr.length, nodeIdStr.data)); + if(UA_NodeId_equal(nodeId, parentNodeId)) { + logAddNode(&server->config.logger, session, nodeId, + "A node cannot have itself as parent"); retval = UA_STATUSCODE_BADINVALIDARGUMENT; goto cleanup; } /* Check parent reference. Objects may have no parent. */ - retval = checkParentReference(server, session, node->nodeClass, - parentNodeId, referenceTypeId); + retval = checkParentReference(server, session, head, parentNodeId, referenceTypeId); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: The parent reference for %.*s is invalid " - "with status code %s", - (int)nodeIdStr.length, nodeIdStr.data, - UA_StatusCode_name(retval))); + logAddNode(&server->config.logger, session, nodeId, + "The parent reference for is invalid"); goto cleanup; } /* Replace empty typeDefinition with the most permissive default */ - if((node->nodeClass == UA_NODECLASS_VARIABLE || - node->nodeClass == UA_NODECLASS_OBJECT) && + if((head->nodeClass == UA_NODECLASS_VARIABLE || + head->nodeClass == UA_NODECLASS_OBJECT) && UA_NodeId_isNull(typeDefinitionId)) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: No TypeDefinition for %.*s; Use the default " - "TypeDefinition for the Variable/Object", - (int)nodeIdStr.length, nodeIdStr.data)); - if(node->nodeClass == UA_NODECLASS_VARIABLE) + logAddNode(&server->config.logger, session, nodeId, + "No TypeDefinition. Use the default " + "TypeDefinition for the Variable/Object"); + if(head->nodeClass == UA_NODECLASS_VARIABLE) typeDefinitionId = &baseDataVariableType; else typeDefinitionId = &baseObjectType; @@ -39389,126 +42964,100 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, /* Get the type node */ type = UA_NODESTORE_GET(server, typeDefinitionId); if(!type) { - UA_LOG_NODEID_WRAP(typeDefinitionId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Node type %.*s not found", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, nodeId, "Node type not found"); retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; goto cleanup; } UA_Boolean typeOk = false; - switch(node->nodeClass) { + const UA_NodeHead *typeHead = &type->head; + switch(head->nodeClass) { case UA_NODECLASS_DATATYPE: - typeOk = type->nodeClass == UA_NODECLASS_DATATYPE; + typeOk = typeHead->nodeClass == UA_NODECLASS_DATATYPE; break; case UA_NODECLASS_METHOD: - typeOk = type->nodeClass == UA_NODECLASS_METHOD; + typeOk = typeHead->nodeClass == UA_NODECLASS_METHOD; break; case UA_NODECLASS_OBJECT: - typeOk = type->nodeClass == UA_NODECLASS_OBJECTTYPE; - break; case UA_NODECLASS_OBJECTTYPE: - typeOk = type->nodeClass == UA_NODECLASS_OBJECTTYPE; + typeOk = typeHead->nodeClass == UA_NODECLASS_OBJECTTYPE; break; case UA_NODECLASS_REFERENCETYPE: - typeOk = type->nodeClass == UA_NODECLASS_REFERENCETYPE; + typeOk = typeHead->nodeClass == UA_NODECLASS_REFERENCETYPE; break; case UA_NODECLASS_VARIABLE: - typeOk = type->nodeClass == UA_NODECLASS_VARIABLETYPE; - break; case UA_NODECLASS_VARIABLETYPE: - typeOk = type->nodeClass == UA_NODECLASS_VARIABLETYPE; + typeOk = typeHead->nodeClass == UA_NODECLASS_VARIABLETYPE; break; case UA_NODECLASS_VIEW: - typeOk = type->nodeClass == UA_NODECLASS_VIEW; + typeOk = typeHead->nodeClass == UA_NODECLASS_VIEW; break; default: typeOk = false; } if(!typeOk) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Type for %.*s does not match node class", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, nodeId, + "Type does not match the NodeClass"); retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; goto cleanup; } /* See if the type has the correct node class. For type-nodes, we know * that type has the same nodeClass from checkParentReference. */ - if(node->nodeClass == UA_NODECLASS_VARIABLE) { - if(((const UA_VariableTypeNode*)type)->isAbstract) { - /* Get subtypes of the parent reference types */ - UA_NodeId *parentTypeHierarchy = NULL; - size_t parentTypeHierarchySize = 0; - retval |= referenceSubtypes(server, &parentReferences[0], - &parentTypeHierarchySize, &parentTypeHierarchy); - retval |= referenceSubtypes(server, &parentReferences[1], - &parentTypeHierarchySize, &parentTypeHierarchy); - if(retval != UA_STATUSCODE_GOOD) { - UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize, - &UA_TYPES[UA_TYPES_NODEID]); - goto cleanup; - } - - /* Abstract variable is allowed if parent is a children of a - * base data variable. An abstract variable may be part of an - * object type which again is below BaseObjectType */ - const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); - const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); - if(!isNodeInTree(server, parentNodeId, &variableTypes, - parentTypeHierarchy, parentTypeHierarchySize) && - !isNodeInTree(server, parentNodeId, &objectTypes, - parentTypeHierarchy, parentTypeHierarchySize)) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Type of variable node %.*s must " - "be VariableType and not cannot be abstract", - (int)nodeIdStr.length, nodeIdStr.data)); - retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; - } - UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize, - &UA_TYPES[UA_TYPES_NODEID]); - if(retval != UA_STATUSCODE_GOOD) - goto cleanup; + if(head->nodeClass == UA_NODECLASS_VARIABLE && + type->variableTypeNode.isAbstract) { + /* Get subtypes of the parent reference types */ + UA_ReferenceTypeSet refTypes1, refTypes2; + retval |= referenceTypeIndices(server, &parentReferences[0], &refTypes1, true); + retval |= referenceTypeIndices(server, &parentReferences[1], &refTypes2, true); + UA_ReferenceTypeSet refTypes = UA_ReferenceTypeSet_union(refTypes1, refTypes2); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Abstract variable is allowed if parent is a children of a + * base data variable. An abstract variable may be part of an + * object type which again is below BaseObjectType */ + const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); + if(!isNodeInTree(server, parentNodeId, &variableTypes, &refTypes) && + !isNodeInTree(server, parentNodeId, &objectTypes, &refTypes)) { + logAddNode(&server->config.logger, session, nodeId, + "Type of variable node must be a " + "VariableType and not cannot be abstract"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; } } - if(node->nodeClass == UA_NODECLASS_OBJECT) { - if(((const UA_ObjectTypeNode*)type)->isAbstract) { - /* Get subtypes of the parent reference types */ - UA_NodeId *parentTypeHierarchy = NULL; - size_t parentTypeHierarchySize = 0; - retval |= referenceSubtypes(server, &parentReferences[0], - &parentTypeHierarchySize, &parentTypeHierarchy); - retval |= referenceSubtypes(server, &parentReferences[1], - &parentTypeHierarchySize, &parentTypeHierarchy); - if(retval != UA_STATUSCODE_GOOD) { - UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize, - &UA_TYPES[UA_TYPES_NODEID]); - goto cleanup; - } + if(head->nodeClass == UA_NODECLASS_OBJECT && + type->objectTypeNode.isAbstract) { + /* Get subtypes of the parent reference types */ + UA_ReferenceTypeSet refTypes1, refTypes2; + retval |= referenceTypeIndices(server, &parentReferences[0], &refTypes1, true); + retval |= referenceTypeIndices(server, &parentReferences[1], &refTypes2, true); + UA_ReferenceTypeSet refTypes = UA_ReferenceTypeSet_union(refTypes1, refTypes2); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; - /* Object node created of an abstract ObjectType. Only allowed - * if within BaseObjectType folder or if it's an event (subType of BaseEventType) */ - const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); - UA_Boolean isInBaseObjectType = - isNodeInTree(server, parentNodeId, &objectTypes, - parentTypeHierarchy, parentTypeHierarchySize); - - const UA_NodeId eventTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); - UA_Boolean isInBaseEventType = - isNodeInTree(server, &type->nodeId, &eventTypes, &hasSubtype, 1); - - if(!isInBaseObjectType && !(isInBaseEventType && UA_NodeId_isNull(parentNodeId))) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Type of object node %.*s must " - "be ObjectType and not be abstract", - (int)nodeIdStr.length, nodeIdStr.data)); - retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; - } - UA_Array_delete(parentTypeHierarchy, parentTypeHierarchySize, - &UA_TYPES[UA_TYPES_NODEID]); - if(retval != UA_STATUSCODE_GOOD) - goto cleanup; + + /* Object node created of an abstract ObjectType. Only allowed if + * within BaseObjectType folder or if it's an event (subType of + * BaseEventType) */ + const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); + UA_Boolean isInBaseObjectType = + isNodeInTree(server, parentNodeId, &objectTypes, &refTypes); + + const UA_NodeId eventTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); + UA_Boolean isInBaseEventType = + isNodeInTree_singleRef(server, &type->head.nodeId, &eventTypes, + UA_REFERENCETYPEINDEX_HASSUBTYPE); + + if(!isInBaseObjectType && + !(isInBaseEventType && UA_NodeId_isNull(parentNodeId))) { + logAddNode(&server->config.logger, session, nodeId, + "Type of ObjectNode must be ObjectType and not be abstract"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; } } } @@ -39516,33 +43065,30 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, /* Add reference to the parent */ if(!UA_NodeId_isNull(parentNodeId)) { if(UA_NodeId_isNull(referenceTypeId)) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Reference to parent of %.*s cannot be null", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, nodeId, + "Reference to parent cannot be null"); retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; goto cleanup; } - retval = addRef(server, session, &node->nodeId, referenceTypeId, parentNodeId, false); + retval = addRef(server, session, &head->nodeId, referenceTypeId, + parentNodeId, false); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Adding reference to parent of %.*s failed", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, nodeId, + "Adding reference to parent failed"); goto cleanup; } } /* Add a hasTypeDefinition reference */ - if(node->nodeClass == UA_NODECLASS_VARIABLE || - node->nodeClass == UA_NODECLASS_OBJECT) { + if(head->nodeClass == UA_NODECLASS_VARIABLE || + head->nodeClass == UA_NODECLASS_OBJECT) { UA_assert(type != NULL); /* see above */ - retval = addRef(server, session, &node->nodeId, &hasTypeDefinition, &type->nodeId, true); + retval = addRef(server, session, &head->nodeId, &hasTypeDefinition, + &type->head.nodeId, true); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Adding a reference to the type " - "definition of %.*s failed with error code %s", - (int)nodeIdStr.length, nodeIdStr.data, - UA_StatusCode_name(retval))); + logAddNode(&server->config.logger, session, nodeId, + "Adding a reference to the type definition failed"); } } @@ -39560,26 +43106,27 @@ AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext, const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) { /* Do not check access for server */ if(session != &server->adminSession && server->config.accessControl.allowAddNode) { - UA_UNLOCK(server->serviceMutex) - if (!server->config.accessControl.allowAddNode(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, item)) { - UA_LOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); + if(!server->config.accessControl. + allowAddNode(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, item)) { + UA_LOCK(&server->serviceMutex); return UA_STATUSCODE_BADUSERACCESSDENIED; } - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); } /* Check the namespaceindex */ if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) { UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Namespace invalid"); + "AddNode: Namespace invalid"); return UA_STATUSCODE_BADNODEIDINVALID; } if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED && item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) { UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Node attributes invalid"); + "AddNode: Node attributes invalid"); return UA_STATUSCODE_BADINTERNALERROR; } @@ -39587,18 +43134,20 @@ AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext, UA_Node *node = UA_NODESTORE_NEW(server, item->nodeClass); if(!node) { UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Node could not create a node " + "AddNode: Node could not create a node " "in the nodestore"); return UA_STATUSCODE_BADOUTOFMEMORY; } + UA_NodeId tmpOutId = UA_NODEID_NULL; /* Fill the node attributes */ - node->context = nodeContext; - UA_StatusCode retval = UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); + node->head.context = nodeContext; + UA_StatusCode retval = + UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->head.nodeId); if(retval != UA_STATUSCODE_GOOD) goto create_error; - retval = UA_QualifiedName_copy(&item->browseName, &node->browseName); + retval = UA_QualifiedName_copy(&item->browseName, &node->head.browseName); if(retval != UA_STATUSCODE_GOOD) goto create_error; @@ -39608,17 +43157,25 @@ AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext, goto create_error; /* Add the node to the nodestore */ + if(!outNewNodeId) + outNewNodeId = &tmpOutId; retval = UA_NODESTORE_INSERT(server, node, outNewNodeId); - if(retval != UA_STATUSCODE_GOOD) + if(retval != UA_STATUSCODE_GOOD) { UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Node could not add the new node " + "AddNode: Node could not add the new node " "to the nodestore with error code %s", UA_StatusCode_name(retval)); - return retval; + return retval; + } + + if(outNewNodeId == &tmpOutId) + UA_NodeId_clear(&tmpOutId); + + return UA_STATUSCODE_GOOD; create_error: UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Node could not create a node " + "AddNode: Node could not create a node " "with error code %s", UA_StatusCode_name(retval)); UA_NODESTORE_DELETE(server, node); return retval; @@ -39700,7 +43257,8 @@ Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContex /* Set the BrowsenName before adding to the Nodestore. The BrowseName is * immutable afterwards. */ UA_Boolean noBrowseName = UA_QualifiedName_isNull(&item->browseName); - UA_StatusCode retval = checkSetBrowseName(server, session, (UA_AddNodesItem*)(uintptr_t)item); + UA_StatusCode retval = + checkSetBrowseName(server, session, (UA_AddNodesItem*)(uintptr_t)item); if(retval != UA_STATUSCODE_GOOD) return retval; @@ -39724,75 +43282,14 @@ Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContex return retval; } -static UA_StatusCode -recursiveTypeCheckAddChildren(UA_Server *server, UA_Session *session, - const UA_Node **nodeptr, const UA_Node *type) { - UA_assert(type != NULL); - UA_StatusCode retval = UA_STATUSCODE_GOOD; - const UA_Node *node = *nodeptr; - - /* Use attributes from the type. The value and value constraints are the - * same for the variable and variabletype attribute structs. */ - if(node->nodeClass == UA_NODECLASS_VARIABLE || - node->nodeClass == UA_NODECLASS_VARIABLETYPE) { - retval = useVariableTypeAttributes(server, session, (const UA_VariableNode**)nodeptr, - (const UA_VariableTypeNode*)type); - node = *nodeptr; /* If the node was replaced */ - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Using attributes for %.*s from the variable type " - "failed with error code %s", (int)nodeIdStr.length, - nodeIdStr.data, UA_StatusCode_name(retval))); - return retval; - } - - /* Check NodeClass for 'hasSubtype'. UA_NODECLASS_VARIABLE not allowed to have subtype */ - if((node->nodeClass == UA_NODECLASS_VARIABLE) && (UA_NodeId_equal( - &node->references->referenceTypeId, &hasSubtype))) { - UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: VariableType not allowed to have HasSubType"); - return UA_STATUSCODE_BADREFERENCENOTALLOWED; - } - - /* Check if all attributes hold the constraints of the type now. The initial - * attributes must type-check. The constructor might change the attributes - * again. Then, the changes are type-checked by the normal write service. */ - retval = typeCheckVariableNode(server, session, (const UA_VariableNode*)node, - (const UA_VariableTypeNode*)type); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Type-checking the variable node %.*s " - "failed with error code %s", (int)nodeIdStr.length, - nodeIdStr.data, UA_StatusCode_name(retval))); - return retval; - } - } - - /* Add (mandatory) child nodes from the type definition */ - if(node->nodeClass == UA_NODECLASS_VARIABLE || - node->nodeClass == UA_NODECLASS_OBJECT) { - retval = addTypeChildren(server, session, node, type); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Adding child nodes of %.*s failed with error code %s", - (int)nodeIdStr.length, nodeIdStr.data, UA_StatusCode_name(retval))); - } - } - - return UA_STATUSCODE_GOOD; -} - /* Construct children first */ static UA_StatusCode recursiveCallConstructors(UA_Server *server, UA_Session *session, - const UA_Node *node, const UA_Node *type) { - if(node->constructed) - return UA_STATUSCODE_GOOD; - - /* Construct the children */ + const UA_NodeId *nodeId, const UA_Node *type) { + /* Browse the children */ UA_BrowseDescription bd; UA_BrowseDescription_init(&bd); - bd.nodeId = node->nodeId; + bd.nodeId = *nodeId; bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); bd.includeSubtypes = true; bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; @@ -39804,30 +43301,34 @@ recursiveCallConstructors(UA_Server *server, UA_Session *session, if(br.statusCode != UA_STATUSCODE_GOOD) return br.statusCode; - /* Call the constructor for every unconstructed node */ + /* Call the constructor for every unconstructed child node */ UA_StatusCode retval = UA_STATUSCODE_GOOD; for(size_t i = 0; i < br.referencesSize; ++i) { UA_ReferenceDescription *rd = &br.references[i]; + if(!UA_ExpandedNodeId_isLocal(&rd->nodeId)) + continue; const UA_Node *target = UA_NODESTORE_GET(server, &rd->nodeId.nodeId); if(!target) continue; - if(target->constructed) { + if(target->head.constructed) { UA_NODESTORE_RELEASE(server, target); continue; } const UA_Node *targetType = NULL; - if(node->nodeClass == UA_NODECLASS_VARIABLE || - node->nodeClass == UA_NODECLASS_OBJECT) { - targetType = getNodeType(server, target); + if(target->head.nodeClass == UA_NODECLASS_VARIABLE || + target->head.nodeClass == UA_NODECLASS_OBJECT) { + targetType = getNodeType(server, &target->head); if(!targetType) { UA_NODESTORE_RELEASE(server, target); retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; break; } } - retval = recursiveCallConstructors(server, session, target, targetType); + UA_NODESTORE_RELEASE(server, target); + retval = recursiveCallConstructors(server, session, &rd->nodeId.nodeId, targetType); + if(targetType) UA_NODESTORE_RELEASE(server, targetType); if(retval != UA_STATUSCODE_GOOD) @@ -39840,133 +43341,307 @@ recursiveCallConstructors(UA_Server *server, UA_Session *session, if(retval != UA_STATUSCODE_GOOD) return retval; - /* Get the node type constructor */ - const UA_NodeTypeLifecycle *lifecycle = NULL; - if(type && node->nodeClass == UA_NODECLASS_OBJECT) { - const UA_ObjectTypeNode *ot = (const UA_ObjectTypeNode*)type; - lifecycle = &ot->lifecycle; - } else if(type && node->nodeClass == UA_NODECLASS_VARIABLE) { - const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)type; - lifecycle = &vt->lifecycle; - } + /* Get the node context */ + const UA_Node *node = UA_NODESTORE_GET(server, nodeId); + if(!node) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + void *context = node->head.context; + UA_NODESTORE_RELEASE(server, node); /* Call the global constructor */ - void *context = node->context; if(server->config.nodeLifecycle.constructor) { - UA_UNLOCK(server->serviceMutex); - retval = server->config.nodeLifecycle.constructor(server, &session->sessionId, - session->sessionHandle, - &node->nodeId, &context); - UA_LOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); + retval = server->config.nodeLifecycle. + constructor(server, &session->sessionId, + session->sessionHandle, nodeId, &context); + UA_LOCK(&server->serviceMutex); + if(retval != UA_STATUSCODE_GOOD) + return retval; } - /* Call the type constructor */ - if(retval == UA_STATUSCODE_GOOD && lifecycle && lifecycle->constructor) { - UA_UNLOCK(server->serviceMutex) + /* Call the local (per-type) constructor */ + const UA_NodeTypeLifecycle *lifecycle = NULL; + if(type && node->head.nodeClass == UA_NODECLASS_OBJECT) + lifecycle = &type->objectTypeNode.lifecycle; + else if(type && node->head.nodeClass == UA_NODECLASS_VARIABLE) + lifecycle = &type->variableTypeNode.lifecycle; + if(lifecycle && lifecycle->constructor) { + UA_UNLOCK(&server->serviceMutex); retval = lifecycle->constructor(server, &session->sessionId, - session->sessionHandle, &type->nodeId, - type->context, &node->nodeId, &context); - UA_LOCK(server->serviceMutex); + session->sessionHandle, &type->head.nodeId, + type->head.context, nodeId, &context); + UA_LOCK(&server->serviceMutex); + if(retval != UA_STATUSCODE_GOOD) + goto global_destructor; } - if(retval != UA_STATUSCODE_GOOD) - goto fail1; - /* Set the context *and* mark the node as constructed */ - if(retval == UA_STATUSCODE_GOOD) - retval = UA_Server_editNode(server, &server->adminSession, &node->nodeId, - (UA_EditNodeCallback)setConstructedNodeContext, - context); + retval = UA_Server_editNode(server, &server->adminSession, nodeId, + (UA_EditNodeCallback)setConstructedNodeContext, context); + if(retval != UA_STATUSCODE_GOOD) + goto local_destructor; /* All good, return */ - if(retval == UA_STATUSCODE_GOOD) - return retval; + return retval; /* Fail. Call the destructors. */ + local_destructor: if(lifecycle && lifecycle->destructor) { - UA_UNLOCK(server->serviceMutex); - lifecycle->destructor(server, &session->sessionId, - session->sessionHandle, &type->nodeId, - type->context, &node->nodeId, &context); - UA_LOCK(server->serviceMutex) + UA_UNLOCK(&server->serviceMutex); + lifecycle->destructor(server, &session->sessionId, session->sessionHandle, + &type->head.nodeId, type->head.context, nodeId, &context); + UA_LOCK(&server->serviceMutex); } - - fail1: + global_destructor: if(server->config.nodeLifecycle.destructor) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); server->config.nodeLifecycle.destructor(server, &session->sessionId, session->sessionHandle, - &node->nodeId, context); - UA_LOCK(server->serviceMutex); + nodeId, context); + UA_LOCK(&server->serviceMutex); } - return retval; } -static void -recursiveDeconstructNode(UA_Server *server, UA_Session *session, - size_t hierarchicalReferencesSize, - UA_ExpandedNodeId *hierarchicalReferences, - const UA_Node *node); +/* Add new ReferenceType to the subtypes bitfield */ +static UA_StatusCode +addReferenceTypeSubtype(UA_Server *server, UA_Session *session, + UA_Node *node, void *context) { + node->referenceTypeNode.subTypes = + UA_ReferenceTypeSet_union(node->referenceTypeNode.subTypes, + *(UA_ReferenceTypeSet*)context); + return UA_STATUSCODE_GOOD; +} -static void -recursiveDeleteNode(UA_Server *server, UA_Session *session, - size_t hierarchicalReferencesSize, - UA_ExpandedNodeId *hierarchicalReferences, - const UA_Node *node, UA_Boolean removeTargetRefs); +static UA_StatusCode +setReferenceTypeSubtypes(UA_Server *server, const UA_ReferenceTypeNode *node) { + /* Get the ReferenceTypes upwards in the hierarchy */ + size_t parentsSize = 0; + UA_ExpandedNodeId *parents = NULL; + UA_ReferenceTypeSet reftypes_subtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); + UA_StatusCode res = + browseRecursive(server, 1, &node->head.nodeId, UA_BROWSEDIRECTION_INVERSE, + &reftypes_subtype, UA_NODECLASS_UNSPECIFIED, + false, &parentsSize, &parents); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Add the ReferenceTypeIndex of this node */ + const UA_ReferenceTypeSet *newRefSet = &node->subTypes; + for(size_t i = 0; i < parentsSize; i++) { + UA_Server_editNode(server, &server->adminSession, &parents[i].nodeId, + addReferenceTypeSubtype, (void*)(uintptr_t)newRefSet); + } + + UA_Array_delete(parents, parentsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +setVariableNodeDynamic(UA_Server *server, UA_Session *session, + UA_Node *node, const void *_) { + (void)_; /* unused */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE) + ((UA_VariableNode*)node)->isDynamic = true; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +checkSetIsDynamicVariable(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId) { + /* Get all hierarchical reference types */ + UA_ReferenceTypeSet reftypes_hierarchical; + UA_ReferenceTypeSet_init(&reftypes_hierarchical); + UA_NodeId hierarchicalRefs = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); + UA_StatusCode res = + referenceTypeIndices(server, &hierarchicalRefs, &reftypes_hierarchical, true); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Is the variable under the server object? */ + UA_NodeId serverNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER); + if(isNodeInTree(server, nodeId, &serverNodeId, &reftypes_hierarchical)) + return UA_STATUSCODE_GOOD; + + /* Is the variable in the type hierarchy? */ + UA_NodeId typesNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER); + if(isNodeInTree(server, nodeId, &typesNodeId, &reftypes_hierarchical)) + return UA_STATUSCODE_GOOD; + + /* Is the variable a property of a method node (InputArguments / + * OutputArguments)? */ + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = *nodeId; + bd.browseDirection = UA_BROWSEDIRECTION_INVERSE; + bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); + bd.includeSubtypes = false; + bd.nodeClassMask = UA_NODECLASS_METHOD; + UA_BrowseResult br; + UA_BrowseResult_init(&br); + UA_UInt32 maxrefs = 0; + Operation_Browse(server, session, &maxrefs, &bd, &br); + UA_Boolean hasParentMethod = (br.referencesSize > 0); + UA_BrowseResult_clear(&br); + if(hasParentMethod) + return UA_STATUSCODE_GOOD; + + /* Set the variable to "dynamic" */ + UA_Server_editNode(server, session, nodeId, + (UA_EditNodeCallback)setVariableNodeDynamic, NULL); + + return UA_STATUSCODE_GOOD; +} /* Children, references, type-checking, constructors. */ UA_StatusCode AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) { - UA_StatusCode retval = UA_STATUSCODE_GOOD; - /* Get the node */ + const UA_Node *type = NULL; const UA_Node *node = UA_NODESTORE_GET(server, nodeId); if(!node) return UA_STATUSCODE_BADNODEIDUNKNOWN; - const UA_Node *type = NULL; + /* Set the ReferenceTypesSet of subtypes in the ReferenceTypeNode */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) { + retval = setReferenceTypeSubtypes(server, &node->referenceTypeNode); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + } - /* Instantiate variables and objects */ - if(node->nodeClass == UA_NODECLASS_VARIABLE || - node->nodeClass == UA_NODECLASS_VARIABLETYPE || - node->nodeClass == UA_NODECLASS_OBJECT) { - /* Get the type node */ - type = getNodeType(server, node); + /* Check NodeClass for 'hasSubtype'. UA_NODECLASS_VARIABLE not allowed + * to have subtype */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE) { + for(size_t i = 0; i < node->head.referencesSize; i++) { + if(node->head.references[i].referenceTypeIndex == + UA_REFERENCETYPEINDEX_HASSUBTYPE) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Variable not allowed " + "to have HasSubType reference", + (int)nodeIdStr.length, nodeIdStr.data)); + retval = UA_STATUSCODE_BADREFERENCENOTALLOWED; + goto cleanup; + } + } + } + + /* Get the type node */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE || + node->head.nodeClass == UA_NODECLASS_VARIABLETYPE || + node->head.nodeClass == UA_NODECLASS_OBJECT) { + type = getNodeType(server, &node->head); if(!type) { if(server->bootstrapNS0) goto constructor; - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Node type for %.*s not found", - (int)nodeIdStr.length, nodeIdStr.data)); + logAddNode(&server->config.logger, session, &node->head.nodeId, + "Node type not found"); retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; goto cleanup; } + } + + /* Initialize and typecheck the variable */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE || + node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) { + /* Use attributes from the type. The value and value constraints are the + * same for the variable and variabletype attribute structs. */ + retval = useVariableTypeAttributes(server, session, + &node->variableNode, + &type->variableTypeNode); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Using attributes for from " + "the variable type failed with error code %s", + (int)nodeIdStr.length, nodeIdStr.data, + UA_StatusCode_name(retval))); + goto cleanup; + } + + /* Get a new pointer to the node. It might have been switched out */ +#ifdef UA_ENABLE_IMMUTABLE_NODES + UA_NODESTORE_RELEASE(server, node); + node = UA_NODESTORE_GET(server, nodeId); + if(!node || (node->head.nodeClass != UA_NODECLASS_VARIABLE && + node->head.nodeClass != UA_NODECLASS_VARIABLETYPE)) { + retval = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } +#endif + + /* Check if all attributes hold the constraints of the type now. The initial + * attributes must type-check. The constructor might change the attributes + * again. Then, the changes are type-checked by the normal write service. */ + retval = typeCheckVariableNode(server, session, &node->variableNode, + &type->variableTypeNode); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Type-checking " + "failed with error code %s", (int)nodeIdStr.length, + nodeIdStr.data, UA_StatusCode_name(retval))); + goto cleanup; + } + } - retval = recursiveTypeCheckAddChildren(server, session, &node, type); + /* Add (mandatory) child nodes from the type definition */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE || + node->head.nodeClass == UA_NODECLASS_OBJECT) { + retval = addTypeChildren(server, session, nodeId, &type->head.nodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Adding child nodes " + "failed with error code %s", (int)nodeIdStr.length, + nodeIdStr.data, UA_StatusCode_name(retval))); + goto cleanup; + } + } + + /* Add (mandatory) child nodes from the HasInterface references */ + if(node->head.nodeClass == UA_NODECLASS_OBJECT) { + retval = addInterfaceChildren(server, session, nodeId, &type->head.nodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Adding child nodes " + "interface failed with error code %s", + (int)nodeIdStr.length, nodeIdStr.data, + UA_StatusCode_name(retval))); + goto cleanup; + } + } + + /* Set variables to dynamic (source and server timestamps are meaningful) if + * they fulfill some conditions */ + if(node->head.nodeClass == UA_NODECLASS_VARIABLE) { + retval = checkSetIsDynamicVariable(server, session, nodeId); if(retval != UA_STATUSCODE_GOOD) goto cleanup; } /* Call the constructor(s) */ constructor: - retval = recursiveCallConstructors(server, session, node, type); + if(!node->head.constructed) + retval = recursiveCallConstructors(server, session, nodeId, type); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_NODEID_WRAP(&node->nodeId, UA_LOG_INFO_SESSION(&server->config.logger, session, - "AddNodes: Calling the node constructor(s) of %.*s failed " - "with status code %s", (int)nodeIdStr.length, - nodeIdStr.data, UA_StatusCode_name(retval))); + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, + "AddNode (%.*s): Calling the node constructor(s) " + "failed with status code %s", (int)nodeIdStr.length, + nodeIdStr.data, UA_StatusCode_name(retval))); } cleanup: if(type) UA_NODESTORE_RELEASE(server, type); - if(retval != UA_STATUSCODE_GOOD) { - recursiveDeconstructNode(server, session, 0, NULL, node); - recursiveDeleteNode(server, session, 0, NULL, node, true); - } - UA_NODESTORE_RELEASE(server, node); + if(node) + UA_NODESTORE_RELEASE(server, node); + if(retval != UA_STATUSCODE_GOOD) + deleteNode(server, *nodeId, true); return retval; } @@ -39974,7 +43649,8 @@ static void Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext, const UA_AddNodesItem *item, UA_AddNodesResult *result) { result->statusCode = - Operation_addNode_begin(server, session, nodeContext, item, &item->parentNodeId.nodeId, + Operation_addNode_begin(server, session, nodeContext, + item, &item->parentNodeId.nodeId, &item->referenceTypeId, &result->addedNodeId); if(result->statusCode != UA_STATUSCODE_GOOD) return; @@ -39992,7 +43668,7 @@ Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request, UA_AddNodesResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing AddNodesRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxNodesPerNodeManagement != 0 && request->nodesToAddSize > server->config.maxNodesPerNodeManagement) { @@ -40003,21 +43679,19 @@ Service_AddNodes(UA_Server *server, UA_Session *session, response->responseHeader.serviceResult = UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_addNode, NULL, - &request->nodesToAddSize, &UA_TYPES[UA_TYPES_ADDNODESITEM], - &response->resultsSize, &UA_TYPES[UA_TYPES_ADDNODESRESULT]); + &request->nodesToAddSize, + &UA_TYPES[UA_TYPES_ADDNODESITEM], + &response->resultsSize, + &UA_TYPES[UA_TYPES_ADDNODESRESULT]); } UA_StatusCode -addNode(UA_Server *server, const UA_NodeClass nodeClass, - const UA_NodeId *requestedNewNodeId, - const UA_NodeId *parentNodeId, - const UA_NodeId *referenceTypeId, - const UA_QualifiedName browseName, - const UA_NodeId *typeDefinition, - const UA_NodeAttributes *attr, - const UA_DataType *attributeType, +addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId *requestedNewNodeId, + const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, + const UA_QualifiedName browseName, const UA_NodeId *typeDefinition, + const UA_NodeAttributes *attr, const UA_DataType *attributeType, void *nodeContext, UA_NodeId *outNewNodeId) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); /* Create the AddNodesItem */ UA_AddNodesItem item; @@ -40028,9 +43702,8 @@ addNode(UA_Server *server, const UA_NodeClass nodeClass, item.parentNodeId.nodeId = *parentNodeId; item.referenceTypeId = *referenceTypeId; item.typeDefinition.nodeId = *typeDefinition; - item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; - item.nodeAttributes.content.decoded.type = attributeType; - item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; + UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, + (void*)(uintptr_t)attr, attributeType); /* Call the normal addnodes service */ UA_AddNodesResult result; @@ -40053,44 +43726,44 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeAttributes *attr, const UA_DataType *attributeType, void *nodeContext, UA_NodeId *outNewNodeId) { - UA_LOCK(server->serviceMutex) - UA_StatusCode reval = addNode(server, nodeClass, requestedNewNodeId, parentNodeId, - referenceTypeId, browseName, typeDefinition, attr, attributeType, nodeContext, outNewNodeId); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_StatusCode reval = + addNode(server, nodeClass, requestedNewNodeId, parentNodeId, + referenceTypeId, browseName, typeDefinition, attr, + attributeType, nodeContext, outNewNodeId); + UA_UNLOCK(&server->serviceMutex); return reval; } UA_StatusCode UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass, - const UA_NodeId requestedNewNodeId, - const UA_NodeId parentNodeId, - const UA_NodeId referenceTypeId, - const UA_QualifiedName browseName, - const UA_NodeId typeDefinition, - const void *attr, const UA_DataType *attributeType, - void *nodeContext, UA_NodeId *outNewNodeId) { + const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, const void *attr, + const UA_DataType *attributeType, void *nodeContext, + UA_NodeId *outNewNodeId) { UA_AddNodesItem item; UA_AddNodesItem_init(&item); item.nodeClass = nodeClass; item.requestedNewNodeId.nodeId = requestedNewNodeId; item.browseName = browseName; item.typeDefinition.nodeId = typeDefinition; - item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; - item.nodeAttributes.content.decoded.type = attributeType; - item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; + UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, + (void*)(uintptr_t)attr, attributeType); - UA_LOCK(server->serviceMutex); - UA_StatusCode retval = Operation_addNode_begin(server, &server->adminSession, nodeContext, &item, - &parentNodeId, &referenceTypeId, outNewNodeId); - UA_UNLOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + Operation_addNode_begin(server, &server->adminSession, nodeContext, &item, + &parentNodeId, &referenceTypeId, outNewNodeId); + UA_UNLOCK(&server->serviceMutex); return retval; } UA_StatusCode UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = AddNode_finish(server, &server->adminSession, &nodeId); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -40104,177 +43777,182 @@ Operation_deleteReference(UA_Server *server, UA_Session *session, void *context, /* Remove references to this node (in the other nodes) */ static void -removeIncomingReferences(UA_Server *server, UA_Session *session, - const UA_Node *node) { +removeIncomingReferences(UA_Server *server, UA_Session *session, const UA_NodeHead *head) { UA_DeleteReferencesItem item; UA_DeleteReferencesItem_init(&item); - item.targetNodeId.nodeId = node->nodeId; + item.targetNodeId.nodeId = head->nodeId; item.deleteBidirectional = false; + UA_StatusCode dummy; - for(size_t i = 0; i < node->referencesSize; ++i) { - UA_NodeReferenceKind *refs = &node->references[i]; - item.isForward = refs->isInverse; - item.referenceTypeId = refs->referenceTypeId; - for(size_t j = 0; j < refs->refTargetsSize; ++j) { - item.sourceNodeId = refs->refTargets[j].targetId.nodeId; + for(size_t i = 0; i < head->referencesSize; ++i) { + const UA_NodeReferenceKind *rk = &head->references[i]; + item.isForward = rk->isInverse; + item.referenceTypeId = + *UA_NODESTORE_GETREFERENCETYPEID(server, rk->referenceTypeIndex); + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + if(!UA_NodePointer_isLocal(t->targetId)) + continue; + item.sourceNodeId = UA_NodePointer_toNodeId(t->targetId); Operation_deleteReference(server, session, NULL, &item, &dummy); } } } -/* A node can only be deleted if it has at most one incoming hierarchical - * reference. If hierarchicalReferences is NULL, always remove. */ +/* A node is auto-deleted if all its hierarchical parents are being deleted */ static UA_Boolean -multipleHierarchies(size_t hierarchicalRefsSize, UA_ExpandedNodeId *hierarchicalRefs, - const UA_Node *node) { - if(!hierarchicalRefs) - return false; - - size_t incomingRefs = 0; - for(size_t i = 0; i < node->referencesSize; i++) { - const UA_NodeReferenceKind *k = &node->references[i]; - if(!k->isInverse) +hasParentRef(const UA_NodeHead *head, const UA_ReferenceTypeSet *refSet, + RefTree *refTree) { + for(size_t i = 0; i < head->referencesSize; i++) { + const UA_NodeReferenceKind *rk = &head->references[i]; + if(!rk->isInverse) continue; - - UA_Boolean hierarchical = false; - for(size_t j = 0; j < hierarchicalRefsSize; j++) { - if(UA_NodeId_equal(&hierarchicalRefs[j].nodeId, - &k->referenceTypeId)) { - hierarchical = true; - break; - } - } - if(!hierarchical) + if(!UA_ReferenceTypeSet_contains(refSet, rk->referenceTypeIndex)) continue; - - incomingRefs += k->refTargetsSize; - if(incomingRefs > 1) - return true; + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + if(!UA_NodePointer_isLocal(t->targetId)) + continue; + UA_NodeId tmpId = UA_NodePointer_toNodeId(t->targetId); + if(!RefTree_containsNodeId(refTree, &tmpId)) + return true; + } } - return false; } -/* Recursively call the destructors of this node and all child nodes. - * Deconstructs the parent before its children. */ static void -recursiveDeconstructNode(UA_Server *server, UA_Session *session, - size_t hierarchicalRefsSize, - UA_ExpandedNodeId *hierarchicalRefs, - const UA_Node *node) { - /* Was the constructor called for the node? */ - if(!node->constructed) - return; +deconstructNodeSet(UA_Server *server, UA_Session *session, + UA_ReferenceTypeSet *hierarchRefsSet, RefTree *refTree) { + /* Deconstruct the nodes based on the RefTree entries, parent nodes first */ + for(size_t i = 0; i < refTree->size; i++) { + const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[i].nodeId); + if(!member) + continue; - /* Call the type-level destructor */ - void *context = node->context; /* No longer needed after this function */ - if(node->nodeClass == UA_NODECLASS_OBJECT || - node->nodeClass == UA_NODECLASS_VARIABLE) { - const UA_Node *type = getNodeType(server, node); - if(type) { - const UA_NodeTypeLifecycle *lifecycle; - if(node->nodeClass == UA_NODECLASS_OBJECT) - lifecycle = &((const UA_ObjectTypeNode*)type)->lifecycle; - else - lifecycle = &((const UA_VariableTypeNode*)type)->lifecycle; - if(lifecycle->destructor) { - UA_UNLOCK(server->serviceMutex); - lifecycle->destructor(server, - &session->sessionId, session->sessionHandle, - &type->nodeId, type->context, - &node->nodeId, &context); - UA_LOCK(server->serviceMutex); + /* Call the type-level destructor */ + void *context = member->head.context; /* No longer needed after this function */ + if(member->head.nodeClass == UA_NODECLASS_OBJECT || + member->head.nodeClass == UA_NODECLASS_VARIABLE) { + const UA_Node *type = getNodeType(server, &member->head); + if(type) { + /* Get the lifecycle */ + const UA_NodeTypeLifecycle *lifecycle; + if(member->head.nodeClass == UA_NODECLASS_OBJECT) + lifecycle = &type->objectTypeNode.lifecycle; + else + lifecycle = &type->variableTypeNode.lifecycle; + + /* Call the destructor */ + if(lifecycle->destructor) { + UA_UNLOCK(&server->serviceMutex); + lifecycle->destructor(server, + &session->sessionId, session->sessionHandle, + &type->head.nodeId, type->head.context, + &member->head.nodeId, &context); + UA_LOCK(&server->serviceMutex); + } + + /* Release the type node */ + UA_NODESTORE_RELEASE(server, type); } - UA_NODESTORE_RELEASE(server, type); } - } - /* Call the global destructor */ - if(server->config.nodeLifecycle.destructor) { - UA_UNLOCK(server->serviceMutex); - server->config.nodeLifecycle.destructor(server, &session->sessionId, - session->sessionHandle, - &node->nodeId, context); - UA_LOCK(server->serviceMutex); - } + /* Call the global destructor */ + if(server->config.nodeLifecycle.destructor) { + UA_UNLOCK(&server->serviceMutex); + server->config.nodeLifecycle.destructor(server, &session->sessionId, + session->sessionHandle, + &member->head.nodeId, context); + UA_LOCK(&server->serviceMutex); + } - /* Set the constructed flag to false */ - UA_Server_editNode(server, &server->adminSession, &node->nodeId, - (UA_EditNodeCallback)setDeconstructedNode, context); + /* Release the node. Don't access the node context from here on. */ + UA_NODESTORE_RELEASE(server, member); - /* Browse to get all children of the node */ - UA_BrowseDescription bd; - UA_BrowseDescription_init(&bd); - bd.nodeId = node->nodeId; - bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); - bd.includeSubtypes = true; - bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; + /* Set the constructed flag to false */ + UA_Server_editNode(server, &server->adminSession, &refTree->targets[i].nodeId, + (UA_EditNodeCallback)setDeconstructedNode, NULL); + } +} - UA_BrowseResult br; - UA_BrowseResult_init(&br); - UA_UInt32 maxrefs = 0; - Operation_Browse(server, session, &maxrefs, &bd, &br); - if(br.statusCode != UA_STATUSCODE_GOOD) - return; +/* The processNodeLayer function searches all children's of the head node and + * adds the children node to the RefTree if all incoming references sources are + * contained in the RefTree (No external references to this node --> node can be + * deleted) */ +static UA_StatusCode +autoDeleteChildren(UA_Server *server, UA_Session *session, RefTree *refTree, + const UA_ReferenceTypeSet *hierarchRefsSet, const UA_NodeHead *head){ + UA_StatusCode res = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < head->referencesSize; ++i) { + /* Check if the ReferenceType is hierarchical */ + UA_NodeReferenceKind *refs = &head->references[i]; + if(!UA_ReferenceTypeSet_contains(hierarchRefsSet, refs->referenceTypeIndex)) + continue; - /* Deconstruct every child node */ - for(size_t i = 0; i < br.referencesSize; ++i) { - UA_ReferenceDescription *rd = &br.references[i]; - const UA_Node *child = UA_NODESTORE_GET(server, &rd->nodeId.nodeId); - if(!child) + /* Check if the references are forward (to a child) */ + if(refs->isInverse) continue; - /* Only delete child nodes that have no other parent */ - if(!multipleHierarchies(hierarchicalRefsSize, hierarchicalRefs, child)) - recursiveDeconstructNode(server, session, hierarchicalRefsSize, - hierarchicalRefs, child); - UA_NODESTORE_RELEASE(server, child); - } - UA_BrowseResult_clear(&br); -} + /* Loop over the references */ + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(refs, t))) { + /* Get the child */ + const UA_Node *child = UA_NODESTORE_GETFROMREF(server, t->targetId); + if(!child) + continue; -static void -recursiveDeleteNode(UA_Server *server, UA_Session *session, - size_t hierarchicalRefsSize, - UA_ExpandedNodeId *hierarchicalRefs, - const UA_Node *node, UA_Boolean removeTargetRefs) { - /* Browse to get all children of the node */ - UA_BrowseDescription bd; - UA_BrowseDescription_init(&bd); - bd.nodeId = node->nodeId; - bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); - bd.includeSubtypes = true; - bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; + /* Only delete child nodes that have no other parent */ + if(!hasParentRef(&child->head, hierarchRefsSet, refTree)) + res = RefTree_addNodeId(refTree, &child->head.nodeId, NULL); + UA_NODESTORE_RELEASE(server, child); + if(res != UA_STATUSCODE_GOOD) + return res; + } + } + return UA_STATUSCODE_GOOD; +} - UA_BrowseResult br; - UA_BrowseResult_init(&br); - UA_UInt32 maxrefs = 0; - Operation_Browse(server, session, &maxrefs, &bd, &br); - if(br.statusCode != UA_STATUSCODE_GOOD) - return; +/* Build up an ordered set (tree) of all nodes that can be deleted. Step through + * the ordered set in order to avoid recursion. */ +static UA_StatusCode +buildDeleteNodeSet(UA_Server *server, UA_Session *session, + const UA_ReferenceTypeSet *hierarchRefsSet, + const UA_NodeId *initial, UA_Boolean removeTargetRefs, + RefTree *refTree) { + /* Add the initial node to delete */ + UA_StatusCode res = RefTree_addNodeId(refTree, initial, NULL); + if(res != UA_STATUSCODE_GOOD) + return res; - /* Remove every child */ - for(size_t i = 0; i < br.referencesSize; ++i) { - UA_ReferenceDescription *rd = &br.references[i]; - /* Check for self-reference to avoid endless loop */ - if(UA_NodeId_equal(&node->nodeId, &rd->nodeId.nodeId)) - continue; - const UA_Node *child = UA_NODESTORE_GET(server, &rd->nodeId.nodeId); - if(!child) + /* Find out which hierarchical children should also be deleted. We know + * there are no "external" ExpandedNodeId in the RefTree. */ + size_t pos = 0; + while(pos < refTree->size) { + const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[pos].nodeId); + pos++; + if(!member) continue; - /* Only delete child nodes that have no other parent */ - if(!multipleHierarchies(hierarchicalRefsSize, hierarchicalRefs, child)) - recursiveDeleteNode(server, session, hierarchicalRefsSize, - hierarchicalRefs, child, true); - UA_NODESTORE_RELEASE(server, child); + res |= autoDeleteChildren(server, session, refTree, hierarchRefsSet, &member->head); + UA_NODESTORE_RELEASE(server, member); } + return res; +} - UA_BrowseResult_clear(&br); - - if(removeTargetRefs) - removeIncomingReferences(server, session, node); - - UA_NODESTORE_REMOVE(server, &node->nodeId); +static void +deleteNodeSet(UA_Server *server, UA_Session *session, + const UA_ReferenceTypeSet *hierarchRefsSet, + UA_Boolean removeTargetRefs, RefTree *refTree) { + /* Delete the nodes based on the RefTree entries */ + for(size_t i = refTree->size; i > 0; --i) { + const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[i-1].nodeId); + if(!member) + continue; + UA_NODESTORE_RELEASE(server, member); + if(removeTargetRefs) + removeIncomingReferences(server, session, &member->head); + UA_NODESTORE_REMOVE(server, &member->head.nodeId); + } } static void @@ -40282,14 +43960,15 @@ deleteNodeOperation(UA_Server *server, UA_Session *session, void *context, const UA_DeleteNodesItem *item, UA_StatusCode *result) { /* Do not check access for server */ if(session != &server->adminSession && server->config.accessControl.allowDeleteNode) { - UA_UNLOCK(server->serviceMutex); - if ( !server->config.accessControl.allowDeleteNode(server, &server->config.accessControl, - &session->sessionId, session->sessionHandle, item)) { - UA_LOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); + if(!server->config.accessControl. + allowDeleteNode(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, item)) { + UA_LOCK(&server->serviceMutex); *result = UA_STATUSCODE_BADUSERACCESSDENIED; return; } - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); } const UA_Node *node = UA_NODESTORE_GET(server, &item->nodeId); @@ -40298,10 +43977,11 @@ deleteNodeOperation(UA_Server *server, UA_Session *session, void *context, return; } - if(UA_Node_hasSubTypeOrInstances(node)) { - UA_LOG_INFO_SESSION(&server->config.logger, session, - "Delete Nodes: Cannot delete a type node " - "with active instances or subtypes"); + if(UA_Node_hasSubTypeOrInstances(&node->head)) { + UA_LOG_NODEID_INFO(&node->head.nodeId, + UA_LOG_INFO_SESSION(&server->config.logger, session, "DeleteNode (%.*s): " + "Cannot delete a type node with active instances or " + "subtypes", (int)nodeIdStr.length, nodeIdStr.data)); UA_NODESTORE_RELEASE(server, node); *result = UA_STATUSCODE_BADINTERNALERROR; return; @@ -40310,35 +43990,51 @@ deleteNodeOperation(UA_Server *server, UA_Session *session, void *context, /* TODO: Check if the information model consistency is violated */ /* TODO: Check if the node is a mandatory child of a parent */ + /* Relase the node. Don't access the pointer after this! */ + UA_NODESTORE_RELEASE(server, node); + /* A node can be referenced with hierarchical references from several * parents in the information model. (But not in a circular way.) The * hierarchical references are checked to see if a node can be deleted. * Getting the type hierarchy can fail in case of low RAM. In that case the * nodes are always deleted. */ - UA_ExpandedNodeId *hierarchicalRefs = NULL; - size_t hierarchicalRefsSize = 0; + UA_ReferenceTypeSet hierarchRefsSet; UA_NodeId hr = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); - browseRecursive(server, 1, &hr, 1, &subtypeId, UA_BROWSEDIRECTION_FORWARD, true, - &hierarchicalRefsSize, &hierarchicalRefs); - if(!hierarchicalRefs) { + *result = referenceTypeIndices(server, &hr, &hierarchRefsSet, true); + if(*result != UA_STATUSCODE_GOOD) + return; + + /* The list of childs is needed for the deconstructing and deleting phase. + * Within the processNodeLayer we generate a RefTree based set of childs + * which can be deleted beside the parent node. */ + RefTree refTree; + *result = RefTree_init(&refTree); + if(*result != UA_STATUSCODE_GOOD) + return; + *result = buildDeleteNodeSet(server, session, &hierarchRefsSet, &item->nodeId, + item->deleteTargetReferences, &refTree); + if(*result != UA_STATUSCODE_GOOD) { UA_LOG_WARNING_SESSION(&server->config.logger, session, - "Delete Nodes: Cannot test for hierarchical " - "references. Deleting the node and all child nodes."); + "DeleteNode: Incomplete lookup of nodes. " + "Still deleting what we have."); + /* Continue, so the RefTree is cleaned up. Return the error message + * anyway. */ } - recursiveDeconstructNode(server, session, hierarchicalRefsSize, hierarchicalRefs, node); - recursiveDeleteNode(server, session, hierarchicalRefsSize, hierarchicalRefs, node, - item->deleteTargetReferences); - UA_Array_delete(hierarchicalRefs, hierarchicalRefsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); - - UA_NODESTORE_RELEASE(server, node); + + /* Deconstruct, then delete, then clean up the set */ + deconstructNodeSet(server, session, &hierarchRefsSet, &refTree); + deleteNodeSet(server, session, &hierarchRefsSet, + item->deleteTargetReferences, &refTree); + RefTree_clear(&refTree); } -void Service_DeleteNodes(UA_Server *server, UA_Session *session, - const UA_DeleteNodesRequest *request, - UA_DeleteNodesResponse *response) { +void +Service_DeleteNodes(UA_Server *server, UA_Session *session, + const UA_DeleteNodesRequest *request, + UA_DeleteNodesResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing DeleteNodesRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxNodesPerNodeManagement != 0 && request->nodesToDeleteSize > server->config.maxNodesPerNodeManagement) { @@ -40351,22 +44047,23 @@ void Service_DeleteNodes(UA_Server *server, UA_Session *session, (UA_ServiceOperation)deleteNodeOperation, NULL, &request->nodesToDeleteSize, &UA_TYPES[UA_TYPES_DELETENODESITEM], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } UA_StatusCode UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, UA_Boolean deleteReferences) { - UA_LOCK(server->serviceMutex) + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = deleteNode(server, nodeId, deleteReferences); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } UA_StatusCode deleteNode(UA_Server *server, const UA_NodeId nodeId, UA_Boolean deleteReferences) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_DeleteNodesItem item; item.deleteTargetReferences = deleteReferences; item.nodeId = nodeId; @@ -40380,62 +44077,96 @@ deleteNode(UA_Server *server, const UA_NodeId nodeId, /******************/ struct AddNodeInfo { - const UA_AddReferencesItem *item; - UA_UInt32 browseNameHash; + UA_Byte refTypeIndex; + UA_Boolean isForward; + const UA_ExpandedNodeId *targetNodeId; + UA_UInt32 targetBrowseNameHash; }; static UA_StatusCode -addOneWayReference(UA_Server *server, UA_Session *session, - UA_Node *node, const struct AddNodeInfo *info) { - return UA_Node_addReference(node, info->item, info->browseNameHash); +addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, + const struct AddNodeInfo *info) { + return UA_Node_addReference(node, info->refTypeIndex, info->isForward, + info->targetNodeId, info->targetBrowseNameHash); } static UA_StatusCode deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const UA_DeleteReferencesItem *item) { - return UA_Node_deleteReference(node, item); + const UA_Node *refType = UA_NODESTORE_GET(server, &item->referenceTypeId); + if(!refType) + return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + if(refType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) { + UA_NODESTORE_RELEASE(server, refType); + return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + } + UA_Byte refTypeIndex = refType->referenceTypeNode.referenceTypeIndex; + UA_NODESTORE_RELEASE(server, refType); + return UA_Node_deleteReference(node, refTypeIndex, item->isForward, &item->targetNodeId); } static void Operation_addReference(UA_Server *server, UA_Session *session, void *context, const UA_AddReferencesItem *item, UA_StatusCode *retval) { - /* Do not check access for server */ + (void)context; + UA_assert(session); + + /* Check access rights */ if(session != &server->adminSession && server->config.accessControl.allowAddReference) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); if (!server->config.accessControl. allowAddReference(server, &server->config.accessControl, &session->sessionId, session->sessionHandle, item)) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); *retval = UA_STATUSCODE_BADUSERACCESSDENIED; return; } - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); } - /* Currently no expandednodeids are allowed */ + /* TODO: Currently no expandednodeids are allowed */ if(item->targetServerUri.length > 0) { *retval = UA_STATUSCODE_BADNOTIMPLEMENTED; return; } - /* Get the source and target nodes */ + /* Check the ReferenceType and get the index */ + const UA_Node *refType = UA_NODESTORE_GET(server, &item->referenceTypeId); + if(!refType) { + *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + return; + } + if(refType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) { + UA_NODESTORE_RELEASE(server, refType); + *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + return; + } + UA_Byte refTypeIndex = refType->referenceTypeNode.referenceTypeIndex; + UA_NODESTORE_RELEASE(server, refType); + + /* Get the source and target node BrowseName hash */ const UA_Node *targetNode = UA_NODESTORE_GET(server, &item->targetNodeId.nodeId); if(!targetNode) { *retval = UA_STATUSCODE_BADTARGETNODEIDINVALID; return; } + UA_UInt32 targetNameHash = UA_QualifiedName_hash(&targetNode->head.browseName); + UA_NODESTORE_RELEASE(server, targetNode); + const UA_Node *sourceNode = UA_NODESTORE_GET(server, &item->sourceNodeId); - if(!targetNode) { - UA_NODESTORE_RELEASE(server, targetNode); + if(!sourceNode) { *retval = UA_STATUSCODE_BADSOURCENODEIDINVALID; return; } + UA_UInt32 sourceNameHash = UA_QualifiedName_hash(&sourceNode->head.browseName); + UA_NODESTORE_RELEASE(server, sourceNode); /* Compute the BrowseName hash and release the target */ struct AddNodeInfo info; - info.item = item; - info.browseNameHash = UA_QualifiedName_hash(&targetNode->browseName); - UA_NODESTORE_RELEASE(server, targetNode); + info.refTypeIndex = refTypeIndex; + info.targetNodeId = &item->targetNodeId; + info.isForward = item->isForward; + info.targetBrowseNameHash = targetNameHash; /* Add the first direction */ *retval = UA_Server_editNode(server, session, &item->sourceNodeId, @@ -40444,54 +44175,57 @@ Operation_addReference(UA_Server *server, UA_Session *session, void *context, if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) { *retval = UA_STATUSCODE_GOOD; firstExisted = true; - } else if(*retval != UA_STATUSCODE_GOOD) { - UA_NODESTORE_RELEASE(server, sourceNode); - return; } + if(*retval != UA_STATUSCODE_GOOD) + return; /* Add the second direction */ - UA_AddReferencesItem secondItem; - UA_AddReferencesItem_init(&secondItem); - secondItem.sourceNodeId = item->targetNodeId.nodeId; - secondItem.referenceTypeId = item->referenceTypeId; - secondItem.isForward = !item->isForward; - secondItem.targetNodeId.nodeId = item->sourceNodeId; - info.item = &secondItem; - info.browseNameHash = UA_QualifiedName_hash(&sourceNode->browseName); - /* keep default secondItem.targetNodeClass = UA_NODECLASS_UNSPECIFIED */ - *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId, + UA_ExpandedNodeId target2; + UA_ExpandedNodeId_init(&target2); + target2.nodeId = item->sourceNodeId; + info.targetNodeId = &target2; + info.isForward = !info.isForward; + info.targetBrowseNameHash = sourceNameHash; + *retval = UA_Server_editNode(server, session, &item->targetNodeId.nodeId, (UA_EditNodeCallback)addOneWayReference, &info); - UA_NODESTORE_RELEASE(server, sourceNode); - /* remove reference if the second direction failed */ - UA_Boolean secondExisted = false; + /* Second direction existed already */ if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) { + /* Calculate common duplicate reference not allowed result and set bad + * result if BOTH directions already existed */ + if(UA_NodeId_equal(&item->sourceNodeId, &item->targetNodeId.nodeId)) { + *retval = UA_STATUSCODE_GOOD; + UA_LOG_INFO_SESSION(&server->config.logger, session, "The source node and the target node are identical. The check for duplicate references is skipped."); + } + else if(firstExisted) { + *retval = UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED; + return; + } *retval = UA_STATUSCODE_GOOD; - secondExisted = true; - } else if(*retval != UA_STATUSCODE_GOOD && !firstExisted) { + } + + /* Remove first direction if the second direction failed */ + if(*retval != UA_STATUSCODE_GOOD && !firstExisted) { UA_DeleteReferencesItem deleteItem; deleteItem.sourceNodeId = item->sourceNodeId; deleteItem.referenceTypeId = item->referenceTypeId; deleteItem.isForward = item->isForward; deleteItem.targetNodeId = item->targetNodeId; deleteItem.deleteBidirectional = false; - /* ignore returned status code */ + /* Ignore status code */ UA_Server_editNode(server, session, &item->sourceNodeId, (UA_EditNodeCallback)deleteOneWayReference, &deleteItem); } - - /* Calculate common duplicate reference not allowed result and set bad result - * if BOTH directions already existed */ - if(firstExisted && secondExisted) - *retval = UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED; } -void Service_AddReferences(UA_Server *server, UA_Session *session, - const UA_AddReferencesRequest *request, - UA_AddReferencesResponse *response) { +void +Service_AddReferences(UA_Server *server, UA_Session *session, + const UA_AddReferencesRequest *request, + UA_AddReferencesResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing AddReferencesRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + UA_assert(session); if(server->config.maxNodesPerNodeManagement != 0 && request->referencesToAddSize > server->config.maxNodesPerNodeManagement) { @@ -40504,7 +44238,8 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, (UA_ServiceOperation)Operation_addReference, NULL, &request->referencesToAddSize, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } UA_StatusCode @@ -40520,9 +44255,9 @@ UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, item.targetNodeId = targetId; UA_StatusCode retval = UA_STATUSCODE_GOOD; - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Operation_addReference(server, &server->adminSession, NULL, &item, &retval); - UA_UNLOCK(server->serviceMutex) + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -40534,22 +44269,24 @@ static void Operation_deleteReference(UA_Server *server, UA_Session *session, void *context, const UA_DeleteReferencesItem *item, UA_StatusCode *retval) { /* Do not check access for server */ - if(session != &server->adminSession && server->config.accessControl.allowDeleteReference) { - UA_UNLOCK(server->serviceMutex); + if(session != &server->adminSession && + server->config.accessControl.allowDeleteReference) { + UA_UNLOCK(&server->serviceMutex); if (!server->config.accessControl. allowDeleteReference(server, &server->config.accessControl, &session->sessionId, session->sessionHandle, item)){ - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); *retval = UA_STATUSCODE_BADUSERACCESSDENIED; return; } - UA_LOCK(server->serviceMutex) + UA_LOCK(&server->serviceMutex); } // TODO: Check consistency constraints, remove the references. *retval = UA_Server_editNode(server, session, &item->sourceNodeId, (UA_EditNodeCallback)deleteOneWayReference, - /* cast away const qualifier because callback uses it anyway */ + /* cast away const qualifier because callback + * uses it anyway */ (UA_DeleteReferencesItem *)(uintptr_t)item); if(*retval != UA_STATUSCODE_GOOD) return; @@ -40574,7 +44311,7 @@ Service_DeleteReferences(UA_Server *server, UA_Session *session, UA_DeleteReferencesResponse *response) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Processing DeleteReferencesRequest"); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(server->config.maxNodesPerNodeManagement != 0 && request->referencesToDeleteSize > server->config.maxNodesPerNodeManagement) { @@ -40587,7 +44324,8 @@ Service_DeleteReferences(UA_Server *server, UA_Session *session, (UA_ServiceOperation)Operation_deleteReference, NULL, &request->referencesToDeleteSize, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], - &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + &response->resultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); } UA_StatusCode @@ -40603,9 +44341,9 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, item.deleteBidirectional = deleteBidirectional; UA_StatusCode retval = UA_STATUSCODE_GOOD; - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); Operation_deleteReference(server, &server->adminSession, NULL, &item, &retval); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -40616,24 +44354,23 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, static UA_StatusCode setValueCallback(UA_Server *server, UA_Session *session, UA_VariableNode *node, const UA_ValueCallback *callback) { - if(node->nodeClass != UA_NODECLASS_VARIABLE) + if(node->head.nodeClass != UA_NODECLASS_VARIABLE) return UA_STATUSCODE_BADNODECLASSINVALID; node->value.data.callback = *callback; return UA_STATUSCODE_GOOD; } - - UA_StatusCode UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId, const UA_ValueCallback callback) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId, (UA_EditNodeCallback)setValueCallback, - /* cast away const because callback uses const anyway */ + /* cast away const because + * callback uses const anyway */ (UA_ValueCallback *)(uintptr_t) &callback); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -40643,9 +44380,12 @@ UA_Server_setVariableNode_valueCallback(UA_Server *server, UA_StatusCode UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId, - const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, - const UA_QualifiedName browseName, const UA_NodeId typeDefinition, - const UA_VariableAttributes attr, const UA_DataSource dataSource, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_NodeId typeDefinition, + const UA_VariableAttributes attr, + const UA_DataSource dataSource, void *nodeContext, UA_NodeId *outNewNodeId) { UA_AddNodesItem item; UA_AddNodesItem_init(&item); @@ -40656,16 +44396,15 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested UA_ExpandedNodeId_init(&typeDefinitionId); typeDefinitionId.nodeId = typeDefinition; item.typeDefinition = typeDefinitionId; - item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; - item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr; - item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]; + UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, (void*)(uintptr_t)&attr, + &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]); UA_NodeId newNodeId; if(!outNewNodeId) { newNodeId = UA_NODEID_NULL; outNewNodeId = &newNodeId; } - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); /* Create the node and add it to the nodestore */ UA_StatusCode retval = AddNode_raw(server, &server->adminSession, nodeContext, &item, outNewNodeId); @@ -40687,7 +44426,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested retval = AddNode_finish(server, &server->adminSession, outNewNodeId); cleanup: - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); if(outNewNodeId == &newNodeId) UA_NodeId_clear(&newNodeId); @@ -40696,8 +44435,8 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested static UA_StatusCode setDataSource(UA_Server *server, UA_Session *session, - UA_VariableNode* node, const UA_DataSource *dataSource) { - if(node->nodeClass != UA_NODECLASS_VARIABLE) + UA_VariableNode *node, const UA_DataSource *dataSource) { + if(node->head.nodeClass != UA_NODECLASS_VARIABLE) return UA_STATUSCODE_BADNODECLASSINVALID; if(node->valueSource == UA_VALUESOURCE_DATA) UA_DataValue_clear(&node->value.data.value); @@ -40709,7 +44448,7 @@ setDataSource(UA_Server *server, UA_Session *session, UA_StatusCode setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, const UA_DataSource dataSource) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); return UA_Server_editNode(server, &server->adminSession, &nodeId, (UA_EditNodeCallback)setDataSource, /* casting away const because callback casts it back anyway */ @@ -40719,12 +44458,84 @@ setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, UA_StatusCode UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, const UA_DataSource dataSource) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = setVariableNode_dataSource(server, nodeId, dataSource); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } +/******************************/ +/* Set External Value Source */ +/******************************/ +static UA_StatusCode +setExternalValueSource(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_ValueBackend *externalValueSource) { + if(node->head.nodeClass != UA_NODECLASS_VARIABLE) + return UA_STATUSCODE_BADNODECLASSINVALID; + node->valueBackend.backendType = UA_VALUEBACKENDTYPE_EXTERNAL; + node->valueBackend.backend.external.value = + externalValueSource->backend.external.value; + node->valueBackend.backend.external.callback.notificationRead = + externalValueSource->backend.external.callback.notificationRead; + node->valueBackend.backend.external.callback.userWrite = + externalValueSource->backend.external.callback.userWrite; + return UA_STATUSCODE_GOOD; +} + +/****************************/ +/* Set Data Source Callback */ +/****************************/ +static UA_StatusCode +setDataSourceCallback(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_DataSource *dataSource) { + if(node->head.nodeClass != UA_NODECLASS_VARIABLE) + return UA_STATUSCODE_BADNODECLASSINVALID; + node->valueBackend.backendType = UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK; + node->valueBackend.backend.dataSource.read = dataSource->read; + node->valueBackend.backend.dataSource.write = dataSource->write; + return UA_STATUSCODE_GOOD; +} + +/**********************/ +/* Set Value Backend */ +/**********************/ + +UA_StatusCode +UA_Server_setVariableNode_valueBackend(UA_Server *server, const UA_NodeId nodeId, + const UA_ValueBackend valueBackend){ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_LOCK(&server->serviceMutex); + switch(valueBackend.backendType){ + case UA_VALUEBACKENDTYPE_NONE: + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADCONFIGURATIONERROR; + case UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK: + retval = UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback) setDataSourceCallback, + (UA_DataSource *)(uintptr_t) &valueBackend.backend.dataSource); + break; + case UA_VALUEBACKENDTYPE_INTERNAL: + break; + case UA_VALUEBACKENDTYPE_EXTERNAL: + retval = UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback) setExternalValueSource, + /* cast away const because callback uses const anyway */ + (UA_ValueCallback *)(uintptr_t) &valueBackend); + break; + } + + + // UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId, + // (UA_EditNodeCallback)setValueCallback, + /* cast away const because callback uses const anyway */ + // (UA_ValueCallback *)(uintptr_t) &callback); + + + UA_UNLOCK(&server->serviceMutex); + return retval; +} + + /************************************/ /* Special Handling of Method Nodes */ /************************************/ @@ -40735,11 +44546,14 @@ static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPRO static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPERTYTYPE}}; static UA_StatusCode -UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId, UA_MethodCallback method, - const size_t inputArgumentsSize, const UA_Argument *inputArguments, +UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId, + UA_MethodCallback method, + const size_t inputArgumentsSize, + const UA_Argument *inputArguments, const UA_NodeId inputArgumentsRequestedNewNodeId, UA_NodeId *inputArgumentsOutNewNodeId, - const size_t outputArgumentsSize, const UA_Argument *outputArguments, + const size_t outputArgumentsSize, + const UA_Argument *outputArguments, const UA_NodeId outputArgumentsRequestedNewNodeId, UA_NodeId *outputArgumentsOutNewNodeId) { /* Browse to see which argument nodes exist */ @@ -40844,20 +44658,24 @@ error: deleteNode(server, inputArgsId, true); deleteNode(server, outputArgsId, true); UA_BrowseResult_clear(&br); - return retval; } UA_StatusCode UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId, UA_MethodCallback method, - size_t inputArgumentsSize, const UA_Argument* inputArguments, - size_t outputArgumentsSize, const UA_Argument* outputArguments) { - UA_LOCK(server->serviceMutex) - UA_StatusCode retval = UA_Server_addMethodNodeEx_finish(server, nodeId, method, - inputArgumentsSize, inputArguments, UA_NODEID_NULL, NULL, - outputArgumentsSize, outputArguments, UA_NODEID_NULL, NULL); - UA_UNLOCK(server->serviceMutex) + size_t inputArgumentsSize, + const UA_Argument* inputArguments, + size_t outputArgumentsSize, + const UA_Argument* outputArguments) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + UA_Server_addMethodNodeEx_finish(server, nodeId, method, + inputArgumentsSize, inputArguments, + UA_NODEID_NULL, NULL, + outputArgumentsSize, outputArguments, + UA_NODEID_NULL, NULL); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -40879,21 +44697,19 @@ UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId, item.nodeClass = UA_NODECLASS_METHOD; item.requestedNewNodeId.nodeId = requestedNewNodeId; item.browseName = browseName; - item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; - item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr; - item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_METHODATTRIBUTES]; - + UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, (void*)(uintptr_t)&attr, + &UA_TYPES[UA_TYPES_METHODATTRIBUTES]); UA_NodeId newId; if(!outNewNodeId) { UA_NodeId_init(&newId); outNewNodeId = &newId; } - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = Operation_addNode_begin(server, &server->adminSession, nodeContext, &item, &parentNodeId, &referenceTypeId, outNewNodeId); if(retval != UA_STATUSCODE_GOOD) { - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -40904,7 +44720,7 @@ UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId, outputArgumentsSize, outputArguments, outputArgumentsRequestedNewNodeId, outputArgumentsOutNewNodeId); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); if(outNewNodeId == &newId) UA_NodeId_clear(&newId); return retval; @@ -40912,70 +44728,93 @@ UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId, static UA_StatusCode editMethodCallback(UA_Server *server, UA_Session* session, - UA_Node* node, void* handle) { - if(node->nodeClass != UA_NODECLASS_METHOD) + UA_Node *node, UA_MethodCallback methodCallback) { + if(node->head.nodeClass != UA_NODECLASS_METHOD) return UA_STATUSCODE_BADNODECLASSINVALID; - UA_MethodNode *mnode = (UA_MethodNode*) node; - mnode->method = (UA_MethodCallback)(uintptr_t)handle; + node->methodNode.method = methodCallback; return UA_STATUSCODE_GOOD; } -UA_StatusCode +static UA_StatusCode setMethodNode_callback(UA_Server *server, - const UA_NodeId methodNodeId, - UA_MethodCallback methodCallback) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + const UA_NodeId methodNodeId, + UA_MethodCallback methodCallback) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); return UA_Server_editNode(server, &server->adminSession, &methodNodeId, - (UA_EditNodeCallback)editMethodCallback, - (void*)(uintptr_t)methodCallback); + (UA_EditNodeCallback)editMethodCallback, + (void*)(uintptr_t)methodCallback); } UA_StatusCode -UA_Server_setMethodNode_callback(UA_Server *server, - const UA_NodeId methodNodeId, - UA_MethodCallback methodCallback) { - UA_LOCK(server->serviceMutex); +UA_Server_setMethodNodeCallback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback methodCallback) { + UA_LOCK(&server->serviceMutex); UA_StatusCode retVal = setMethodNode_callback(server, methodNodeId, methodCallback); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retVal; } +UA_StatusCode +UA_Server_getMethodNodeCallback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback *outMethodCallback) { + UA_LOCK(&server->serviceMutex); + const UA_Node *node = UA_NODESTORE_GET(server, &methodNodeId); + if(!node) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNODEIDUNKNOWN; + } + + if(node->head.nodeClass != UA_NODECLASS_METHOD) { + UA_NODESTORE_RELEASE(server, node); + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNODECLASSINVALID; + } + + *outMethodCallback = node->methodNode.method; + UA_NODESTORE_RELEASE(server, node); + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_GOOD; +} + #endif /************************/ /* Lifecycle Management */ /************************/ +void UA_EXPORT +UA_Server_setAdminSessionContext(UA_Server *server, + void *context) { + server->adminSession.sessionHandle = context; +} + static UA_StatusCode setNodeTypeLifecycle(UA_Server *server, UA_Session *session, - UA_Node* node, UA_NodeTypeLifecycle *lifecycle) { - if(node->nodeClass == UA_NODECLASS_OBJECTTYPE) { - UA_ObjectTypeNode *ot = (UA_ObjectTypeNode*)node; - ot->lifecycle = *lifecycle; - return UA_STATUSCODE_GOOD; - } - - if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) { - UA_VariableTypeNode *vt = (UA_VariableTypeNode*)node; - vt->lifecycle = *lifecycle; - return UA_STATUSCODE_GOOD; + UA_Node *node, UA_NodeTypeLifecycle *lifecycle) { + if(node->head.nodeClass == UA_NODECLASS_OBJECTTYPE) { + node->objectTypeNode.lifecycle = *lifecycle; + } else if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) { + node->variableTypeNode.lifecycle = *lifecycle; + } else { + return UA_STATUSCODE_BADNODECLASSINVALID; } - - return UA_STATUSCODE_BADNODECLASSINVALID; + return UA_STATUSCODE_GOOD; } UA_StatusCode UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId, UA_NodeTypeLifecycle lifecycle) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId, (UA_EditNodeCallback)setNodeTypeLifecycle, &lifecycle); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_services_discovery_multicast.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_services_discovery_multicast.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -40989,7 +44828,7 @@ UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId, #if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) -#if UA_MULTITHREADING >= 200 +#if UA_MULTITHREADING >= 100 static void * multicastWorkerLoop(UA_Server *server) { @@ -41068,8 +44907,8 @@ addMdnsRecordForNetworkLayer(UA_Server *server, const UA_String *appName, retval = UA_Discovery_addRecord(server, appName, &hostname, port, &path, UA_DISCOVERY_TCP, true, - server->config.discovery.mdns.serverCapabilities, - server->config.discovery.mdns.serverCapabilitiesSize, + server->config.mdnsConfig.serverCapabilities, + server->config.mdnsConfig.serverCapabilitiesSize, true); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_NETWORK, @@ -41081,14 +44920,14 @@ addMdnsRecordForNetworkLayer(UA_Server *server, const UA_String *appName, } void startMulticastDiscoveryServer(UA_Server *server) { - UA_String *appName = &server->config.discovery.mdns.mdnsServerName; + UA_String *appName = &server->config.mdnsConfig.mdnsServerName; for(size_t i = 0; i < server->config.networkLayersSize; i++) addMdnsRecordForNetworkLayer(server, appName, &server->config.networkLayers[i]); /* find any other server on the net */ UA_Discovery_multicastQuery(server); -#if UA_MULTITHREADING >= 200 +#if UA_MULTITHREADING >= 100 multicastListenStart(server); # endif } @@ -41110,12 +44949,12 @@ stopMulticastDiscoveryServer(UA_Server *server) { if (retval != UA_STATUSCODE_GOOD) continue; - UA_Discovery_removeRecord(server, &server->config.discovery.mdns.mdnsServerName, + UA_Discovery_removeRecord(server, &server->config.mdnsConfig.mdnsServerName, &hostname, port, true); } -#if UA_MULTITHREADING >= 200 +#if UA_MULTITHREADING >= 100 multicastListenStop(server); # else // send out last package with TTL = 0 @@ -41123,28 +44962,37 @@ stopMulticastDiscoveryServer(UA_Server *server) { # endif } -/* All filter criteria must be fulfilled */ +/* All filter criteria must be fulfilled in the list entry. The comparison is case + * insensitive. + * @returns true if the entry matches the filter. False if the filter does not match. + * */ static UA_Boolean -filterServerRecord(size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter, +entryMatchesCapabilityFilter(size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter, serverOnNetwork_list_entry* current) { - // if the element has no capabilities defined, but the filter expects some, then do not use this entry - if (serverCapabilityFilterSize > 0 && current->serverOnNetwork.serverCapabilitiesSize == 0) - return false; + // if the entry has less capabilities defined than the filter, there's no match + if (serverCapabilityFilterSize > current->serverOnNetwork.serverCapabilitiesSize) + return UA_FALSE; for(size_t i = 0; i < serverCapabilityFilterSize; i++) { - for(size_t j = 0; j < current->serverOnNetwork.serverCapabilitiesSize; j++) - if(!UA_String_equal(&serverCapabilityFilter[i], - ¤t->serverOnNetwork.serverCapabilities[j])) - return false; + UA_Boolean capabilityFound = UA_FALSE; + for(size_t j = 0; j < current->serverOnNetwork.serverCapabilitiesSize; j++) { + if(UA_String_equal_ignorecase(&serverCapabilityFilter[i], + ¤t->serverOnNetwork.serverCapabilities[j])) { + capabilityFound = UA_TRUE; + break; + } + } + if (!capabilityFound) + return UA_FALSE; // entry does not match capability } - return true; + return UA_TRUE; } void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session, const UA_FindServersOnNetworkRequest *request, UA_FindServersOnNetworkResponse *response) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); - if (!server->config.discovery.mdnsEnable) { + if (!server->config.mdnsEnabled) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED; return; } @@ -41174,7 +45022,7 @@ void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session, break; if(current->serverOnNetwork.recordId < request->startingRecordId) continue; - if(!filterServerRecord(request->serverCapabilityFilterSize, + if(!entryMatchesCapabilityFilter(request->serverCapabilityFilterSize, request->serverCapabilityFilter, current)) continue; filtered[filteredCount++] = ¤t->serverOnNetwork; @@ -41246,10 +45094,10 @@ void UA_Server_setServerOnNetworkCallback(UA_Server *server, UA_Server_serverOnNetworkCallback cb, void* data) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); server->discoveryManager.serverOnNetworkCallback = cb; server->discoveryManager.serverOnNetworkCallbackData = data; - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); } static void @@ -41579,7 +45427,7 @@ iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat, #endif /* defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/client/ua_client.c" ***********************************/ +/**** amalgamated original file "/src/client/ua_client.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -41598,6 +45446,7 @@ iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat, * Copyright 2016 (c) Lykurg * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB * Copyright 2018 (c) Kalycito Infotech Private Limited + * Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart */ @@ -41628,14 +45477,14 @@ UA_Client_newWithConfig(const UA_ClientConfig *config) { } static void -UA_ClientConfig_deleteMembers(UA_ClientConfig *config) { - UA_ApplicationDescription_deleteMembers(&config->clientDescription); +UA_ClientConfig_clear(UA_ClientConfig *config) { + UA_ApplicationDescription_clear(&config->clientDescription); - UA_ExtensionObject_deleteMembers(&config->userIdentityToken); - UA_String_deleteMembers(&config->securityPolicyUri); + UA_ExtensionObject_clear(&config->userIdentityToken); + UA_String_clear(&config->securityPolicyUri); - UA_EndpointDescription_deleteMembers(&config->endpoint); - UA_UserTokenPolicy_deleteMembers(&config->userTokenPolicy); + UA_EndpointDescription_clear(&config->endpoint); + UA_UserTokenPolicy_clear(&config->userTokenPolicy); if(config->certificateVerification.clear) config->certificateVerification.clear(&config->certificateVerification); @@ -41653,10 +45502,16 @@ UA_ClientConfig_deleteMembers(UA_ClientConfig *config) { config->logger.clear(config->logger.context); config->logger.log = NULL; config->logger.clear = NULL; + + if (config->sessionLocaleIdsSize > 0 && config->sessionLocaleIds) { + UA_Array_delete(config->sessionLocaleIds, config->sessionLocaleIdsSize, &UA_TYPES[UA_TYPES_LOCALEID]); + } + config->sessionLocaleIds = NULL; + config->sessionLocaleIdsSize = 0; } static void -UA_Client_deleteMembers(UA_Client *client) { +UA_Client_clear(UA_Client *client) { /* Delete the async service calls with BADHSUTDOWN */ UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN); @@ -41672,13 +45527,13 @@ UA_Client_deleteMembers(UA_Client *client) { #endif /* Delete the timed work */ - UA_Timer_deleteMembers(&client->timer); + UA_Timer_clear(&client->timer); } void UA_Client_delete(UA_Client* client) { - UA_Client_deleteMembers(client); - UA_ClientConfig_deleteMembers(&client->config); + UA_Client_clear(client); + UA_ClientConfig_clear(&client->config); UA_free(client); } @@ -41701,9 +45556,9 @@ UA_Client_getConfig(UA_Client *client) { } #if UA_LOGLEVEL <= 300 -static const char *channelStateTexts[8] = { - "Closed", "HELSent", "HELReceived", "ACKSent", - "AckReceived", "OPNSent", "Open", "Closing"}; +static const char *channelStateTexts[9] = { + "Fresh", "HELSent", "HELReceived", "ACKSent", + "AckReceived", "OPNSent", "Open", "Closing", "Closed"}; static const char *sessionStateTexts[6] = {"Closed", "CreateRequested", "Created", "ActivateRequested", "Activated", "Closing"}; @@ -41769,7 +45624,9 @@ static UA_StatusCode sendSymmetricServiceRequest(UA_Client *client, const void *request, const UA_DataType *requestType, UA_UInt32 *requestId) { /* Renew SecureChannel if necessary */ - renewSecureChannel(client); + UA_Client_renewSecureChannel(client); + if(client->connectStatus != UA_STATUSCODE_GOOD) + return client->connectStatus; /* Adjusting the request header. The const attribute is violated, but we * only touch the following members: */ @@ -41786,8 +45643,8 @@ sendSymmetricServiceRequest(UA_Client *client, const void *request, (unsigned)rqId, requestType->typeName); #else UA_LOG_DEBUG_CHANNEL(&client->config.logger, &client->channel, - "Sending request with RequestId %u of type %" PRIi16, - (unsigned)rqId, requestType->binaryEncodingId); + "Sending request with RequestId %u of type %" PRIu32, + (unsigned)rqId, requestType->binaryEncodingId.identifier.numeric); #endif /* Send the message */ @@ -41828,9 +45685,8 @@ processAsyncResponse(UA_Client *client, UA_UInt32 requestId, const UA_NodeId *re /* Verify the type of the response */ UA_Response response; const UA_DataType *responseType = ac->responseType; - const UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, ac->responseType->binaryEncodingId); UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(!UA_NodeId_equal(responseTypeId, &expectedNodeId)) { + if(!UA_NodeId_equal(responseTypeId, &ac->responseType->binaryEncodingId)) { UA_init(&response, ac->responseType); if(UA_NodeId_equal(responseTypeId, &serviceFaultId)) { /* Decode as a ServiceFault, i.e. only the response header */ @@ -41847,14 +45703,14 @@ processAsyncResponse(UA_Client *client, UA_UInt32 requestId, const UA_NodeId *re } /* Decode the response */ - retval = UA_decodeBinary(responseMessage, offset, &response, responseType, - client->config.customDataTypes); + retval = UA_decodeBinaryInternal(responseMessage, offset, &response, responseType, + client->config.customDataTypes); process: if(retval != UA_STATUSCODE_GOOD) { UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Could not decode the response with id %u due to %s", - requestId, UA_StatusCode_name(retval)); + (unsigned)requestId, UA_StatusCode_name(retval)); response.responseHeader.serviceResult = retval; } else if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { /* Decode as a ServiceFault, i.e. only the response header */ @@ -41876,7 +45732,7 @@ processAsyncResponse(UA_Client *client, UA_UInt32 requestId, const UA_NodeId *re /* Processes the received service response. Either with an async callback or by * decoding the message and returning it "upwards" in the * SyncResponseDescription. */ -static void +static UA_StatusCode processServiceResponse(void *application, UA_SecureChannel *channel, UA_MessageType messageType, UA_UInt32 requestId, UA_ByteString *message) { @@ -41886,25 +45742,22 @@ processServiceResponse(void *application, UA_SecureChannel *channel, switch(messageType) { case UA_MESSAGETYPE_ACK: processACKResponse(rd->client, message); - return; + return UA_STATUSCODE_GOOD; case UA_MESSAGETYPE_OPN: processOPNResponse(rd->client, message); - return; + return UA_STATUSCODE_GOOD; case UA_MESSAGETYPE_ERR: processERRResponse(rd->client, message); - return; + return UA_STATUSCODE_GOOD; case UA_MESSAGETYPE_MSG: /* Continue below */ break; default: UA_LOG_TRACE_CHANNEL(&rd->client->config.logger, channel, "Invalid message type"); channel->state = UA_SECURECHANNELSTATE_CLOSING; - return; + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; } - /* Forward declaration for the goto */ - UA_NodeId expectedNodeId = UA_NODEID_NULL; - /* Decode the data type identifier of the response */ size_t offset = 0; UA_NodeId responseId; @@ -41923,13 +45776,12 @@ processServiceResponse(void *application, UA_SecureChannel *channel, rd->received = true; /* Check that the response type matches */ - expectedNodeId = UA_NODEID_NUMERIC(0, rd->responseType->binaryEncodingId); - if(!UA_NodeId_equal(&responseId, &expectedNodeId)) { + if(!UA_NodeId_equal(&responseId, &rd->responseType->binaryEncodingId)) { if(UA_NodeId_equal(&responseId, &serviceFaultId)) { UA_init(rd->response, rd->responseType); - retval = UA_decodeBinary(message, &offset, rd->response, - &UA_TYPES[UA_TYPES_SERVICEFAULT], - rd->client->config.customDataTypes); + retval = UA_decodeBinaryInternal(message, &offset, rd->response, + &UA_TYPES[UA_TYPES_SERVICEFAULT], + rd->client->config.customDataTypes); if(retval != UA_STATUSCODE_GOOD) ((UA_ResponseHeader*)rd->response)->serviceResult = retval; UA_LOG_INFO(&rd->client->config.logger, UA_LOGCATEGORY_CLIENT, @@ -41953,11 +45805,11 @@ processServiceResponse(void *application, UA_SecureChannel *channel, #endif /* Decode the response */ - retval = UA_decodeBinary(message, &offset, rd->response, rd->responseType, - rd->client->config.customDataTypes); + retval = UA_decodeBinaryInternal(message, &offset, rd->response, rd->responseType, + rd->client->config.customDataTypes); finish: - UA_NodeId_deleteMembers(&responseId); + UA_NodeId_clear(&responseId); if(retval != UA_STATUSCODE_GOOD) { if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) retval = UA_STATUSCODE_BADRESPONSETOOLARGE; @@ -41970,13 +45822,15 @@ finish: respHeader->serviceResult = retval; } } + + return retval; } /* Receive and process messages until a synchronous message arrives or the * timout finishes */ static UA_StatusCode receiveResponse(UA_Client *client, void *response, const UA_DataType *responseType, - UA_UInt32 timeout, const UA_UInt32 *synchronousRequestId) { + UA_DateTime maxDate, const UA_UInt32 *synchronousRequestId) { /* Prepare the response and the structure we give into processServiceResponse */ SyncResponseDescription rd = { client, false, 0, response, responseType }; @@ -41985,13 +45839,12 @@ receiveResponse(UA_Client *client, void *response, const UA_DataType *responseTy if(synchronousRequestId) rd.requestId = *synchronousRequestId; - UA_DateTime now = UA_DateTime_nowMonotonic(); - UA_DateTime maxDate = now + ((UA_DateTime)timeout * UA_DATETIME_MSEC); UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_DateTime now = UA_DateTime_nowMonotonic(); do { - if(maxDate < now) - return UA_STATUSCODE_GOODNONCRITICALTIMEOUT; UA_UInt32 timeout2 = (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC); + if(maxDate < now) + timeout2 = 0; retval = UA_SecureChannel_receive(&client->channel, &rd, processServiceResponse, timeout2); if(retval == UA_STATUSCODE_GOODNONCRITICALTIMEOUT) break; @@ -42005,6 +45858,8 @@ receiveResponse(UA_Client *client, void *response, const UA_DataType *responseTy break; } now = UA_DateTime_nowMonotonic(); + if(maxDate < now) + break; } while(!rd.received && responseType); /* Return if we don't wait for an async response */ return retval; @@ -42012,7 +45867,8 @@ receiveResponse(UA_Client *client, void *response, const UA_DataType *responseTy UA_StatusCode receiveResponseAsync(UA_Client *client, UA_UInt32 timeout) { - UA_StatusCode res = receiveResponse(client, NULL, NULL, timeout, NULL); + UA_DateTime maxDate = UA_DateTime_nowMonotonic() + ((UA_DateTime)timeout * UA_DATETIME_MSEC); + UA_StatusCode res = receiveResponse(client, NULL, NULL, maxDate, NULL); return (res != UA_STATUSCODE_GOODNONCRITICALTIMEOUT) ? res : UA_STATUSCODE_GOOD; } @@ -42038,7 +45894,8 @@ __UA_Client_Service(UA_Client *client, const void *request, UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response; if(retval == UA_STATUSCODE_GOOD) { /* Retrieve the response */ - retval = receiveResponse(client, response, responseType, client->config.timeout, &requestId); + UA_DateTime maxDate = UA_DateTime_nowMonotonic() + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC); + retval = receiveResponse(client, response, responseType, maxDate, &requestId); } else if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) { respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE; return; @@ -42083,6 +45940,20 @@ void UA_Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCod } } +UA_StatusCode UA_Client_modifyAsyncCallback(UA_Client *client, UA_UInt32 requestId, + void *userdata, UA_ClientAsyncServiceCallback callback) { + AsyncServiceCall *ac; + LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) { + if(ac->requestId == requestId) { + ac->callback = callback; + ac->userdata = userdata; + return UA_STATUSCODE_GOOD; + } + } + + return UA_STATUSCODE_BADNOTFOUND; +} + UA_StatusCode __UA_Client_AsyncServiceEx(UA_Client *client, const void *request, const UA_DataType *requestType, @@ -42093,7 +45964,7 @@ __UA_Client_AsyncServiceEx(UA_Client *client, const void *request, if(client->channel.state != UA_SECURECHANNELSTATE_OPEN) { UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, "SecureChannel must be connected before sending requests"); - return UA_STATUSCODE_BADSERVERNOTCONNECTED; + return UA_STATUSCODE_BADSERVERNOTCONNECTED; } /* Prepare the entry for the linked list */ @@ -42156,13 +46027,14 @@ UA_StatusCode UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback, void *data, UA_Double interval_ms, UA_UInt64 *callbackId) { return UA_Timer_addRepeatedCallback(&client->timer, (UA_ApplicationCallback)callback, - client, data, interval_ms, callbackId); + client, data, interval_ms, NULL, + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, callbackId); } UA_StatusCode UA_Client_changeRepeatedCallbackInterval(UA_Client *client, UA_UInt64 callbackId, UA_Double interval_ms) { - return UA_Timer_changeRepeatedCallbackInterval(&client->timer, callbackId, interval_ms); + return UA_Timer_changeRepeatedCallback(&client->timer, callbackId, interval_ms, NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME); } void @@ -42237,8 +46109,11 @@ UA_StatusCode UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) { /* Process timed (repeated) jobs */ UA_DateTime now = UA_DateTime_nowMonotonic(); - UA_Timer_process(&client->timer, now, - (UA_TimerExecutionCallback)clientExecuteRepeatedCallback, client); + UA_DateTime maxDate = + UA_Timer_process(&client->timer, now, (UA_TimerExecutionCallback) + clientExecuteRepeatedCallback, client); + if(maxDate > now + ((UA_DateTime)timeout * UA_DATETIME_MSEC)) + maxDate = now + ((UA_DateTime)timeout * UA_DATETIME_MSEC); /* Make sure we have an open channel */ UA_StatusCode retval = UA_STATUSCODE_GOOD; @@ -42250,7 +46125,9 @@ UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) { } /* Renew Secure Channel */ - renewSecureChannel(client); + UA_Client_renewSecureChannel(client); + if(client->connectStatus != UA_STATUSCODE_GOOD) + return client->connectStatus; /* Feed the server PublishRequests for the Subscriptions */ #ifdef UA_ENABLE_SUBSCRIPTIONS @@ -42261,7 +46138,7 @@ UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) { UA_Client_backgroundConnectivity(client); /* Listen on the network for the given timeout */ - retval = receiveResponse(client, NULL, NULL, timeout, NULL); + retval = receiveResponse(client, NULL, NULL, maxDate, NULL); if(retval == UA_STATUSCODE_GOODNONCRITICALTIMEOUT) retval = UA_STATUSCODE_GOOD; if(retval != UA_STATUSCODE_GOOD) { @@ -42284,7 +46161,12 @@ UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) { return client->connectStatus; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/client/ua_client_connect.c" ***********************************/ +const UA_DataType * +UA_Client_findDataType(UA_Client *client, const UA_NodeId *typeId) { + return UA_findDataTypeWithCustom(typeId, client->config.customDataTypes); +} + +/**** amalgamated original file "/src/client/ua_client_connect.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -42314,13 +46196,13 @@ getSecurityPolicy(UA_Client *client, UA_String policyUri) { static UA_Boolean endpointUnconfigured(UA_Client *client) { - UA_Byte test = 0; - UA_Byte *pos = (UA_Byte*)&client->config.endpoint; + char test = 0; + char *pos = (char *)&client->config.endpoint; for(size_t i = 0; i < sizeof(UA_EndpointDescription); i++) - test = test | pos[i]; - pos = (UA_Byte*)&client->config.userTokenPolicy; + test = test | *(pos + i); + pos = (char *)&client->config.userTokenPolicy; for(size_t i = 0; i < sizeof(UA_UserTokenPolicy); i++) - test = test | pos[i]; + test = test | *(pos + i); return (test == 0); } @@ -42339,7 +46221,7 @@ signActivateSessionRequest(UA_Client *client, UA_SecureChannel *channel, /* Prepare the signature */ size_t signatureSize = sp->certificateSigningAlgorithm. - getLocalSignatureSize(sp, channel->channelContext); + getLocalSignatureSize(channel->channelContext); UA_StatusCode retval = UA_String_copy(&sp->certificateSigningAlgorithm.uri, &sd->algorithm); if(retval != UA_STATUSCODE_GOOD) @@ -42364,7 +46246,7 @@ signActivateSessionRequest(UA_Client *client, UA_SecureChannel *channel, channel->remoteCertificate.length); memcpy(dataToSign.data + channel->remoteCertificate.length, client->remoteNonce.data, client->remoteNonce.length); - retval = sp->certificateSigningAlgorithm.sign(sp, channel->channelContext, + retval = sp->certificateSigningAlgorithm.sign(channel->channelContext, &dataToSign, &sd->signature); /* Clean up */ @@ -42415,19 +46297,19 @@ encryptUserIdentityToken(UA_Client *client, const UA_String *userTokenSecurityPo /* Compute the encrypted length (at least one byte padding) */ size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule. - encryptionAlgorithm.getRemotePlainTextBlockSize(sp, channelContext); + encryptionAlgorithm.getRemotePlainTextBlockSize(channelContext); + size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemoteBlockSize(channelContext); UA_UInt32 length = (UA_UInt32)(tokenData->length + client->remoteNonce.length); UA_UInt32 totalLength = length + 4; /* Including the length field */ size_t blocks = totalLength / plainTextBlockSize; - if(totalLength % plainTextBlockSize != 0) + if(totalLength % plainTextBlockSize != 0) blocks++; - size_t overHead = - UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(sp, channelContext, - blocks * plainTextBlockSize); + size_t encryptedLength = blocks * encryptedBlockSize; /* Allocate memory for encryption overhead */ UA_ByteString encrypted; - retval = UA_ByteString_allocBuffer(&encrypted, (blocks * plainTextBlockSize) + overHead); + retval = UA_ByteString_allocBuffer(&encrypted, encryptedLength); if(retval != UA_STATUSCODE_GOOD) { sp->channelModule.deleteContext(channelContext); return UA_STATUSCODE_BADOUTOFMEMORY; @@ -42435,9 +46317,10 @@ encryptUserIdentityToken(UA_Client *client, const UA_String *userTokenSecurityPo UA_Byte *pos = encrypted.data; const UA_Byte *end = &encrypted.data[encrypted.length]; - UA_UInt32_encodeBinary(&length, &pos, end); + retval = UA_UInt32_encodeBinary(&length, &pos, end); memcpy(pos, tokenData->data, tokenData->length); memcpy(&pos[tokenData->length], client->remoteNonce.data, client->remoteNonce.length); + UA_assert(retval == UA_STATUSCODE_GOOD); /* Add padding * @@ -42451,8 +46334,8 @@ encryptUserIdentityToken(UA_Client *client, const UA_String *userTokenSecurityPo encrypted.length = paddedLength; retval = sp->asymmetricModule.cryptoModule.encryptionAlgorithm. - encrypt(sp, channelContext, &encrypted); - encrypted.length = (blocks * plainTextBlockSize) + overHead; + encrypt(channelContext, &encrypted); + encrypted.length = encryptedLength; if(iit) { retval |= UA_String_copy(&sp->asymmetricModule.cryptoModule.encryptionAlgorithm.uri, @@ -42496,7 +46379,7 @@ checkCreateSessionSignature(UA_Client *client, const UA_SecureChannel *channel, memcpy(dataToVerify.data + lc->length, client->localNonce.data, client->localNonce.length); - retval = sp->certificateSigningAlgorithm.verify(sp, channel->channelContext, &dataToVerify, + retval = sp->certificateSigningAlgorithm.verify(channel->channelContext, &dataToVerify, &response->serverSignature.signature); UA_ByteString_clear(&dataToVerify); return retval; @@ -42512,9 +46395,11 @@ void processERRResponse(UA_Client *client, const UA_ByteString *chunk) { client->channel.state = UA_SECURECHANNELSTATE_CLOSING; - size_t offset = 8; /* TODO: Make a define for the magic number */ + size_t offset = 0; UA_TcpErrorMessage errMessage; - UA_StatusCode res = UA_TcpErrorMessage_decodeBinary(chunk, &offset, &errMessage); + UA_StatusCode res = + UA_decodeBinaryInternal(chunk, &offset, &errMessage, + &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], NULL); if(res != UA_STATUSCODE_GOOD) { UA_LOG_ERROR_CHANNEL(&client->config.logger, &client->channel, "Received an ERR response that could not be decoded with StatusCode %s", @@ -42543,9 +46428,11 @@ processACKResponse(UA_Client *client, const UA_ByteString *chunk) { UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_NETWORK, "Received ACK message"); /* Decode the message */ - size_t offset = 8; + size_t offset = 0; UA_TcpAcknowledgeMessage ackMessage; - client->connectStatus = UA_TcpAcknowledgeMessage_decodeBinary(chunk, &offset, &ackMessage); + client->connectStatus = + UA_decodeBinaryInternal(chunk, &offset, &ackMessage, + &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], NULL); if(client->connectStatus != UA_STATUSCODE_GOOD) { UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_NETWORK, "Decoding ACK message failed"); @@ -42586,14 +46473,18 @@ sendHELMessage(UA_Client *client) { UA_Byte *bufPos = &message.data[8]; /* skip the header */ const UA_Byte *bufEnd = &message.data[message.length]; - client->connectStatus = UA_TcpHelloMessage_encodeBinary(&hello, &bufPos, bufEnd); + client->connectStatus = + UA_encodeBinaryInternal(&hello, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], + &bufPos, &bufEnd, NULL, NULL); /* Encode the message header at offset 0 */ UA_TcpMessageHeader messageHeader; messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL; messageHeader.messageSize = (UA_UInt32) ((uintptr_t)bufPos - (uintptr_t)message.data); bufPos = message.data; - retval = UA_TcpMessageHeader_encodeBinary(&messageHeader, &bufPos, bufEnd); + retval = UA_encodeBinaryInternal(&messageHeader, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &bufPos, &bufEnd, NULL, NULL); if(retval != UA_STATUSCODE_GOOD) { conn->releaseSendBuffer(conn, &message); return retval; @@ -42611,9 +46502,10 @@ sendHELMessage(UA_Client *client) { return retval; } -static void -processOPNResponseDecoded(UA_Client *client, const UA_ByteString *message, size_t offset) { +void +processOPNResponse(UA_Client *client, const UA_ByteString *message) { /* Is the content of the expected type? */ + size_t offset = 0; UA_NodeId responseId; UA_NodeId expectedId = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE_ENCODING_DEFAULTBINARY); @@ -42631,7 +46523,8 @@ processOPNResponseDecoded(UA_Client *client, const UA_ByteString *message, size_ /* Decode the response */ UA_OpenSecureChannelResponse response; - retval = UA_OpenSecureChannelResponse_decodeBinary(message, &offset, &response); + retval = UA_decodeBinaryInternal(message, &offset, &response, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], NULL); if(retval != UA_STATUSCODE_GOOD) { closeSecureChannel(client); return; @@ -42675,90 +46568,20 @@ processOPNResponseDecoded(UA_Client *client, const UA_ByteString *message, size_ return; } + UA_Float lifetime = (UA_Float)response.securityToken.revisedLifetime / 1000; UA_Boolean renew = (client->channel.state == UA_SECURECHANNELSTATE_OPEN); - if(renew) - UA_LOG_INFO_CHANNEL(&client->config.logger, &client->channel, "SecureChannel renewed"); - else + if(renew) { + UA_LOG_INFO_CHANNEL(&client->config.logger, &client->channel, "SecureChannel " + "renewed with a revised lifetime of %.2fs", lifetime); + } else { UA_LOG_INFO_CHANNEL(&client->config.logger, &client->channel, - "Opened SecureChannel with SecurityPolicy %.*s", + "SecureChannel opened with SecurityPolicy %.*s " + "and a revised lifetime of %.2fs", (int)client->channel.securityPolicy->policyUri.length, - client->channel.securityPolicy->policyUri.data); - - client->channel.state = UA_SECURECHANNELSTATE_OPEN; -} - -void -processOPNResponse(UA_Client *client, UA_ByteString *chunk) { - UA_SecureChannel *channel = &client->channel; - if(channel->state != UA_SECURECHANNELSTATE_OPN_SENT && - channel->state != UA_SECURECHANNELSTATE_OPEN) { - UA_LOG_ERROR_CHANNEL(&client->config.logger, channel, - "Received an unexpected OPN response"); - channel->state = UA_SECURECHANNELSTATE_CLOSING; - return; - } - - /* Skip the first header. We know length and message type. */ - size_t offset = UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH; - - /* Decode the asymmetric algorithm security header and call the callback - * to perform checks. */ - UA_AsymmetricAlgorithmSecurityHeader asymHeader; - UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); - UA_StatusCode retval = - UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(chunk, &offset, &asymHeader); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&client->config.logger, channel, - "Could not decode the OPN header"); - closeSecureChannel(client); - return; - } - - /* Verify the certificate before creating the SecureChannel with it */ - if(asymHeader.senderCertificate.length > 0) { - retval = client->config.certificateVerification. - verifyCertificate(client->config.certificateVerification.context, - &asymHeader.senderCertificate); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&client->config.logger, channel, - "Could not verify the server's certificate"); - closeSecureChannel(client); - return; - } - } - - retval = checkAsymHeader(channel, &asymHeader); - UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&client->config.logger, channel, - "Could not verify the OPN header"); - closeSecureChannel(client); - return; - } - - retval = decryptAndVerifyChunk(channel, &channel->securityPolicy->asymmetricModule.cryptoModule, - UA_MESSAGETYPE_OPN, chunk, offset); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&client->config.logger, channel, - "Could not decrypt and verify the OPN payload"); - closeSecureChannel(client); - return; - } - - /* Decode and verify the sequence header */ - UA_SequenceHeader sequenceHeader; - retval = UA_SequenceHeader_decodeBinary(chunk, &offset, &sequenceHeader); -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - retval |= processSequenceNumberAsym(channel, sequenceHeader.sequenceNumber); -#endif - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_CHANNEL(&client->config.logger, channel, - "Could not process the OPN sequence number"); - closeSecureChannel(client); - return; + client->channel.securityPolicy->policyUri.data, lifetime); } - processOPNResponseDecoded(client, chunk, offset); + client->channel.state = UA_SECURECHANNELSTATE_OPEN; } /* OPN messges to renew the channel are sent asynchronous */ @@ -42817,14 +46640,15 @@ sendOPNAsync(UA_Client *client, UA_Boolean renew) { return UA_STATUSCODE_GOOD; } -void -renewSecureChannel(UA_Client *client) { +UA_StatusCode +UA_Client_renewSecureChannel(UA_Client *client) { /* Check if OPN has been sent or the SecureChannel is still valid */ if(client->channel.state != UA_SECURECHANNELSTATE_OPEN || client->channel.renewState == UA_SECURECHANNELRENEWSTATE_SENT || client->nextChannelRenewal > UA_DateTime_nowMonotonic()) - return; + return UA_STATUSCODE_GOODCALLAGAIN; sendOPNAsync(client, true); + return client->connectStatus; } static void @@ -42850,6 +46674,11 @@ responseActivateSession(UA_Client *client, void *userdata, UA_UInt32 requestId, return; } + /* Replace the nonce */ + UA_ByteString_clear(&client->remoteNonce); + client->remoteNonce = activateResponse->serverNonce; + UA_ByteString_init(&activateResponse->serverNonce); + client->sessionState = UA_SESSIONSTATE_ACTIVATED; notifyClientState(client); } @@ -42866,6 +46695,15 @@ activateSessionAsync(UA_Client *client) { if(retval != UA_STATUSCODE_GOOD) return retval; + if (client->config.sessionLocaleIdsSize && client->config.sessionLocaleIds) { + retval = UA_Array_copy(client->config.sessionLocaleIds, client->config.sessionLocaleIdsSize, + (void **)&request.localeIds, &UA_TYPES[UA_TYPES_LOCALEID]); + if (retval != UA_STATUSCODE_GOOD) + return retval; + + request.localeIdsSize = client->config.sessionLocaleIdsSize; + } + /* If not token is set, use anonymous */ if(request.userIdentityToken.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { UA_AnonymousIdentityToken *t = UA_AnonymousIdentityToken_new(); @@ -42897,8 +46735,15 @@ activateSessionAsync(UA_Client *client) { &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST], (UA_ClientAsyncServiceCallback) responseActivateSession, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE], NULL, NULL); + UA_ActivateSessionRequest_clear(&request); - client->sessionState = UA_SESSIONSTATE_ACTIVATE_REQUESTED; + if(retval == UA_STATUSCODE_GOOD) + client->sessionState = UA_SESSIONSTATE_ACTIVATE_REQUESTED; + else + UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "ActivateSession failed when sending the request with error code %s", + UA_StatusCode_name(retval)); + return retval; } @@ -43038,8 +46883,8 @@ responseGetEndpoints(UA_Client *client, void *userdata, UA_UInt32 requestId, /* Log the selected endpoint */ UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Selected Endpoint %.*s with SecurityMode %s and SecurityPolicy %.*s", - (int)endpoint->endpointUrl.length, endpoint->endpointUrl.data, + "Selected endpoint %lu in URL %.*s with SecurityMode %s and SecurityPolicy %.*s", + (long unsigned)i, (int)endpoint->endpointUrl.length, endpoint->endpointUrl.data, securityModeNames[endpoint->securityMode - 1], (int)endpoint->securityPolicyUri.length, endpoint->securityPolicyUri.data); @@ -43092,13 +46937,17 @@ requestGetEndpoints(UA_Client *client) { request.requestHeader.timestamp = UA_DateTime_now(); request.requestHeader.timeoutHint = 10000; request.endpointUrl = client->endpointUrl; - client->connectStatus = + UA_StatusCode retval = UA_Client_sendAsyncRequest(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], (UA_ClientAsyncServiceCallback) responseGetEndpoints, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE], NULL, NULL); - if(client->connectStatus == UA_STATUSCODE_GOOD) + if(retval == UA_STATUSCODE_GOOD) client->endpointsHandshake = true; - return client->connectStatus; + else + UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "RequestGetEndpoints failed when sending the request with error code %s", + UA_StatusCode_name(retval)); + return retval; } static void @@ -43157,7 +47006,8 @@ createSessionAsync(UA_Client *client) { return retval; } retval = client->channel.securityPolicy->symmetricModule. - generateNonce(client->channel.securityPolicy, &client->localNonce); + generateNonce(client->channel.securityPolicy->policyContext, + &client->localNonce); if(retval != UA_STATUSCODE_GOOD) return retval; } @@ -43187,11 +47037,17 @@ createSessionAsync(UA_Client *client) { if(retval == UA_STATUSCODE_GOOD) client->sessionState = UA_SESSIONSTATE_CREATE_REQUESTED; + else + UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "CreateSession failed when sending the request with error code %s", + UA_StatusCode_name(retval)); - client->connectStatus = retval; - return client->connectStatus; + return retval; } +static UA_StatusCode +initConnect(UA_Client *client); + UA_StatusCode connectIterate(UA_Client *client, UA_UInt32 timeout) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, @@ -43211,18 +47067,16 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) { return UA_STATUSCODE_BADCONNECTIONCLOSED; } - /* TCP connection */ - if(client->connection.state == UA_CONNECTIONSTATE_CLOSED) { - /* Reopen a new TCP connection */ - client->connection = - client->config.initConnectionFunc(client->config.localConnectionConfig, - client->endpointUrl, client->config.timeout, - &client->config.logger); - return client->connectStatus; - } else if(client->connection.state == UA_CONNECTIONSTATE_OPENING) { - /* Poll the connection status */ + /* The connection is closed. Reset the SecureChannel and open a new TCP + * connection */ + if(client->connection.state == UA_CONNECTIONSTATE_CLOSED) + return initConnect(client); + + /* Poll the connection status */ + if(client->connection.state == UA_CONNECTIONSTATE_OPENING) { client->connectStatus = - client->config.pollConnectionFunc(client, &client->connection, timeout); + client->config.pollConnectionFunc(&client->connection, timeout, + &client->config.logger); return client->connectStatus; } @@ -43257,7 +47111,7 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) { /* Open the SecureChannel */ switch(client->channel.state) { - case UA_SECURECHANNELSTATE_CLOSED: + case UA_SECURECHANNELSTATE_FRESH: client->connectStatus = sendHELMessage(client); if(client->connectStatus == UA_STATUSCODE_GOOD) { client->channel.state = UA_SECURECHANNELSTATE_HEL_SENT; @@ -43285,11 +47139,11 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) { switch(client->sessionState) { case UA_SESSIONSTATE_CLOSED: if(!endpointUnconfigured(client)) { - createSessionAsync(client); + client->connectStatus = createSessionAsync(client); return client->connectStatus; } if(!client->endpointsHandshake) { - requestGetEndpoints(client); + client->connectStatus = requestGetEndpoints(client); return client->connectStatus; } receiveResponseAsync(client, timeout); @@ -43299,7 +47153,7 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) { receiveResponseAsync(client, timeout); return client->connectStatus; case UA_SESSIONSTATE_CREATED: - activateSessionAsync(client); + client->connectStatus = activateSessionAsync(client); return client->connectStatus; default: break; @@ -43331,7 +47185,14 @@ verifyClientApplicationURI(const UA_Client *client) { } static UA_StatusCode -initConnect(UA_Client *client, const char *endpointUrl) { +client_configure_securechannel(void *application, UA_SecureChannel *channel, + const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) { + // TODO: Verify if certificate is the same as configured in the client endpoint config + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +initConnect(UA_Client *client) { if(client->connection.state > UA_CONNECTIONSTATE_CLOSED) { UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Client already connected"); @@ -43354,10 +47215,8 @@ initConnect(UA_Client *client, const char *endpointUrl) { /* Initialize the SecureChannel */ UA_SecureChannel_init(&client->channel, &client->config.localConnectionConfig); - - /* Set the endpoint URL the client connects to */ - UA_String_clear(&client->endpointUrl); - client->endpointUrl = UA_STRING_ALLOC(endpointUrl); + client->channel.certificateVerification = &client->config.certificateVerification; + client->channel.processOPNHeader = client_configure_securechannel; if(client->connection.free) client->connection.free(&client->connection); @@ -43380,22 +47239,36 @@ initConnect(UA_Client *client, const char *endpointUrl) { UA_StatusCode UA_Client_connectAsync(UA_Client *client, const char *endpointUrl) { + /* Set the endpoint URL the client connects to */ + UA_String_clear(&client->endpointUrl); + client->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Open a Session when possible */ client->noSession = false; - return initConnect(client, endpointUrl); + + /* Connect Async */ + return initConnect(client); } UA_StatusCode UA_Client_connectSecureChannelAsync(UA_Client *client, const char *endpointUrl) { + /* Set the endpoint URL the client connects to */ + UA_String_clear(&client->endpointUrl); + client->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Don't open a Session */ client->noSession = true; - return initConnect(client, endpointUrl); + + /* Connect Async */ + return initConnect(client); } static UA_StatusCode -connectSync(UA_Client *client, const char *endpointUrl) { +connectSync(UA_Client *client) { UA_DateTime now = UA_DateTime_nowMonotonic(); UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC); - UA_StatusCode retval = initConnect(client, endpointUrl); + UA_StatusCode retval = initConnect(client); if(retval != UA_STATUSCODE_GOOD) return retval; @@ -43407,7 +47280,8 @@ connectSync(UA_Client *client, const char *endpointUrl) { now = UA_DateTime_nowMonotonic(); if(maxDate < now) return UA_STATUSCODE_BADTIMEOUT; - retval = UA_Client_run_iterate(client, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC)); + retval = UA_Client_run_iterate(client, + (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC)); } return retval; @@ -43415,14 +47289,28 @@ connectSync(UA_Client *client, const char *endpointUrl) { UA_StatusCode UA_Client_connect(UA_Client *client, const char *endpointUrl) { + /* Set the endpoint URL the client connects to */ + UA_String_clear(&client->endpointUrl); + client->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Open a Session when possible */ client->noSession = false; - return connectSync(client, endpointUrl); + + /* Connect Synchronous */ + return connectSync(client); } UA_StatusCode UA_Client_connectSecureChannel(UA_Client *client, const char *endpointUrl) { + /* Set the endpoint URL the client connects to */ + UA_String_clear(&client->endpointUrl); + client->endpointUrl = UA_STRING_ALLOC(endpointUrl); + + /* Don't open a Session */ client->noSession = true; - return connectSync(client, endpointUrl); + + /* Connect Synchronous */ + return connectSync(client); } /************************/ @@ -43453,6 +47341,11 @@ closeSecureChannel(UA_Client *client) { /* Set the Session to "Created" if it was "Activated" */ if(client->sessionState > UA_SESSIONSTATE_CREATED) client->sessionState = UA_SESSIONSTATE_CREATED; + + /* Delete outstanding async services - the RequestId is no longr valid. Do + * this after setting the Session state. Otherwise we send out new Publish + * Requests immediately. */ + UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSECURECHANNELCLOSED); } static void @@ -43468,8 +47361,8 @@ sendCloseSession(UA_Client *client) { UA_CloseSessionResponse response; __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST], &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]); - UA_CloseSessionRequest_deleteMembers(&request); - UA_CloseSessionResponse_deleteMembers(&response); + UA_CloseSessionRequest_clear(&request); + UA_CloseSessionResponse_clear(&response); } static void @@ -43478,7 +47371,7 @@ closeSession(UA_Client *client) { if(client->sessionState == UA_SESSIONSTATE_ACTIVATED) sendCloseSession(client); - UA_NodeId_deleteMembers(&client->authenticationToken); + UA_NodeId_clear(&client->authenticationToken); client->requestHandle = 0; client->sessionState = UA_SESSIONSTATE_CLOSED; @@ -43540,7 +47433,7 @@ UA_Client_disconnect(UA_Client *client) { } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/client/ua_client_discovery.c" ***********************************/ +/**** amalgamated original file "/src/client/ua_client_discovery.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -43573,14 +47466,14 @@ UA_Client_getEndpointsInternal(UA_Client *client, const UA_String endpointUrl, UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "GetEndpointRequest failed with error code %s", UA_StatusCode_name(retval)); - UA_GetEndpointsResponse_deleteMembers(&response); + UA_GetEndpointsResponse_clear(&response); return retval; } *endpointDescriptions = response.endpoints; *endpointDescriptionsSize = response.endpointsSize; response.endpoints = NULL; response.endpointsSize = 0; - UA_GetEndpointsResponse_deleteMembers(&response); + UA_GetEndpointsResponse_clear(&response); return UA_STATUSCODE_GOOD; } @@ -43656,7 +47549,7 @@ UA_Client_findServers(UA_Client *client, const char *serverUrl, } /* Clean up */ - UA_FindServersResponse_deleteMembers(&response); + UA_FindServersResponse_clear(&response); if(!connected) UA_Client_disconnect(client); return retval; @@ -43709,7 +47602,7 @@ UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, } /* Clean up */ - UA_FindServersOnNetworkResponse_deleteMembers(&response); + UA_FindServersOnNetworkResponse_clear(&response); if(!connected) UA_Client_disconnect(client); return retval; @@ -43717,13 +47610,13 @@ UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/client/ua_client_highlevel.c" ***********************************/ +/**** amalgamated original file "/src/client/ua_client_highlevel.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2015-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2015-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2015 (c) Oleksiy Vasylyev * Copyright 2017 (c) Florian Palm * Copyright 2016 (c) Chris Iatrou @@ -43733,6 +47626,8 @@ UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, */ +/* The highlevel client API is an "outer onion layer". This file does not + * include ua_client_internal.h on purpose. */ UA_StatusCode UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, @@ -44090,7 +47985,7 @@ __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId, else retval = UA_STATUSCODE_BADUNEXPECTEDERROR; } - if(retval != UA_STATUSCODE_GOOD) { + if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD)) { UA_ReadResponse_clear(&response); return retval; } @@ -44138,7 +48033,7 @@ processReadArrayDimensionsResult(UA_ReadResponse *response, return UA_STATUSCODE_BADUNEXPECTEDERROR; retval = response->results[0].status; - if(retval != UA_STATUSCODE_GOOD) + if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD)) return retval; UA_DataValue *res = &response->results[0]; @@ -44239,7 +48134,7 @@ cleanup: UA_HistoryReadResponse_clear(&response); else retval = UA_STATUSCODE_BADUNEXPECTEDERROR; } - if (retval != UA_STATUSCODE_GOOD) + if (!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD)) goto cleanup; UA_HistoryReadResult *res = response.results; @@ -44467,105 +48362,9 @@ cleanup: } #endif // UA_ENABLE_HISTORIZING +/*******************/ /* Async Functions */ - -typedef struct { - UA_AttributeId attributeId; - const UA_DataType *outDataType; -} AsyncReadData; - -static CustomCallback * -UA_Client_findCustomCallback(UA_Client *client, UA_UInt32 requestId) { - CustomCallback *cc; - LIST_FOREACH(cc, &client->customCallbacks, pointers) { - if(cc->callbackId == requestId) - break; - } - return cc; -} - -static -void ValueAttributeRead(UA_Client *client, void *userdata, - UA_UInt32 requestId, void *response) { - if(!response) - return; - - /* Find the callback for the response */ - CustomCallback *cc = UA_Client_findCustomCallback(client, requestId); - if(!cc) - return; - - UA_ReadResponse *rr = (UA_ReadResponse *) response; - UA_DataValue *res = rr->results; - UA_Boolean done = false; - AsyncReadData *data = (AsyncReadData *)cc->clientData; - if(rr->resultsSize == 1 && res != NULL && res->hasValue) { - if(data->attributeId == UA_ATTRIBUTEID_VALUE) { - /* Call directly with the variant */ - cc->userCallback(client, cc->userData, requestId, &res->value); - done = true; - } else if(UA_Variant_isScalar(&res->value) && - res->value.type == data->outDataType) { - /* Unpack the value */ - UA_STACKARRAY(UA_Byte, value, data->outDataType->memSize); - memcpy(&value, res->value.data, data->outDataType->memSize); - cc->userCallback(client, cc->userData, requestId, &value); - done = true; - } - } - - /* Could not process, delete the callback anyway */ - if(!done) - UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Cannot process the response to the async read " - "request %" PRIu32, requestId); - - UA_free(cc->clientData); - LIST_REMOVE(cc, pointers); - UA_free(cc); -} - -/*Read Attributes*/ -UA_StatusCode -__UA_Client_readAttribute_async(UA_Client *client, - const UA_NodeId *nodeId, UA_AttributeId attributeId, - const UA_DataType *outDataType, UA_ClientAsyncServiceCallback callback, - void *userdata, UA_UInt32 *reqId) { - UA_ReadValueId item; - UA_ReadValueId_init(&item); - item.nodeId = *nodeId; - item.attributeId = attributeId; - UA_ReadRequest request; - UA_ReadRequest_init(&request); - request.nodesToRead = &item; - request.nodesToReadSize = 1; - - CustomCallback *cc = (CustomCallback*) UA_malloc(sizeof(CustomCallback)); - if (!cc) - return UA_STATUSCODE_BADOUTOFMEMORY; - memset(cc, 0, sizeof(CustomCallback)); - cc->userCallback = callback; - cc->userData = userdata; - - cc->clientData = UA_malloc(sizeof(AsyncReadData)); - if(!cc->clientData) { - UA_free(cc); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - AsyncReadData *rd = (AsyncReadData *)cc->clientData; - rd->attributeId = attributeId; - rd->outDataType = outDataType; - - __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST], - ValueAttributeRead, &UA_TYPES[UA_TYPES_READRESPONSE], NULL, - &cc->callbackId); - - LIST_INSERT_HEAD(&client->customCallbacks, cc, pointers); - if (reqId != NULL) - *reqId = cc->callbackId; - - return UA_STATUSCODE_GOOD; -} +/*******************/ /*Write Attributes*/ UA_StatusCode __UA_Client_writeAttribute_async(UA_Client *client, @@ -44652,22 +48451,346 @@ UA_StatusCode __UA_Client_call_async(UA_Client *client, } #endif -UA_StatusCode __UA_Client_translateBrowsePathsToNodeIds_async(UA_Client *client, - char *paths[], UA_UInt32 ids[], size_t pathSize, - UA_ClientAsyncServiceCallback callback, void *userdata, - UA_UInt32 *reqId) { - return UA_STATUSCODE_BADNOTIMPLEMENTED; +/* UA_StatusCode */ +/* UA_Cient_translateBrowsePathsToNodeIds_async(UA_Client *client, char **paths, */ +/* UA_UInt32 *ids, size_t pathSize, */ +/* UA_ClientAsyncTranslateCallback callback, */ +/* void *userdata, UA_UInt32 *reqId) { */ +/* return UA_STATUSCODE_BADNOTIMPLEMENTED; */ +/* } */ + +/*************************/ +/* Read Single Attribute */ +/*************************/ + +typedef struct { + UA_ClientAsyncOperationCallback userCallback; + void *userContext; + const UA_DataType *resultType; /* DataValue -> Value attribute, + * Variant -> ArrayDimensions attribute */ +} UA_AttributeReadContext; + +static void +AttributeReadCallback(UA_Client *client, void *userdata, + UA_UInt32 requestId, UA_ReadResponse *rr) { + UA_AttributeReadContext *ctx = (UA_AttributeReadContext*)userdata; + UA_LOG_DEBUG(&UA_Client_getConfig(client)->logger, UA_LOGCATEGORY_CLIENT, + "Async read response for request %" PRIu32, requestId); + + /* Check the ServiceResult */ + UA_StatusCode res = rr->responseHeader.serviceResult; + if(res != UA_STATUSCODE_GOOD) + goto finish; + + /* Check result array size */ + if(rr->resultsSize != 1) { + res = UA_STATUSCODE_BADINTERNALERROR; + goto finish; + } + + /* A Value attribute */ + UA_DataValue *dv = &rr->results[0]; + if(ctx->resultType == &UA_TYPES[UA_TYPES_DATAVALUE]) { + ctx->userCallback(client, ctx->userContext, requestId, + UA_STATUSCODE_GOOD, dv); + goto finish; + } + + /* An ArrayDimensions attribute. Has to be an array of UInt32. */ + if(ctx->resultType == &UA_TYPES[UA_TYPES_VARIANT]) { + if(dv->hasValue && + UA_Variant_hasArrayType(&dv->value, &UA_TYPES[UA_TYPES_UINT32])) { + ctx->userCallback(client, ctx->userContext, requestId, + UA_STATUSCODE_GOOD, &dv->value); + } else { + res = UA_STATUSCODE_BADINTERNALERROR; + } + goto finish; + } + + /* Check we have a scalar value of the right datatype */ + if(!dv->hasValue || + !UA_Variant_hasScalarType(&dv->value, ctx->resultType)) { + res = UA_STATUSCODE_BADINTERNALERROR; + goto finish; + } + + /* Callback into userland */ + ctx->userCallback(client, ctx->userContext, requestId, + UA_STATUSCODE_GOOD, dv->value.data); + + finish: + if(res != UA_STATUSCODE_GOOD) + ctx->userCallback(client, ctx->userContext, requestId, res, NULL); + UA_free(ctx); +} + +static UA_StatusCode +readAttribute_async(UA_Client *client, const UA_ReadValueId *rvi, + UA_TimestampsToReturn timestampsToReturn, + const UA_DataType *resultType, /* For the specialized reads */ + UA_ClientAsyncOperationCallback callback, + void *userdata, UA_UInt32 *requestId) { + UA_AttributeReadContext *ctx = (UA_AttributeReadContext*) + UA_malloc(sizeof(UA_AttributeReadContext)); + if(!ctx) + return UA_STATUSCODE_BADOUTOFMEMORY; + + ctx->userCallback = callback; + ctx->userContext = userdata; + ctx->resultType = resultType; + + UA_ReadRequest request; + UA_ReadRequest_init(&request); + request.nodesToRead = (UA_ReadValueId*)(uintptr_t)rvi; /* hack, treated as const */ + request.nodesToReadSize = 1; + request.timestampsToReturn = timestampsToReturn; + + UA_StatusCode res = + __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST], + (UA_ClientAsyncServiceCallback)AttributeReadCallback, + &UA_TYPES[UA_TYPES_READRESPONSE], ctx, requestId); + if(res != UA_STATUSCODE_GOOD) + UA_free(ctx); + return res; } UA_StatusCode -UA_Cient_translateBrowsePathsToNodeIds_async(UA_Client *client, char **paths, - UA_UInt32 *ids, size_t pathSize, - UA_ClientAsyncTranslateCallback callback, - void *userdata, UA_UInt32 *reqId) { - return UA_STATUSCODE_BADNOTIMPLEMENTED; +UA_Client_readAttribute_async(UA_Client *client, const UA_ReadValueId *rvi, + UA_TimestampsToReturn timestampsToReturn, + UA_ClientAsyncReadAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_async(client, rvi, timestampsToReturn, + &UA_TYPES[UA_TYPES_DATAVALUE], /* special handling */ + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +/* Helper to keep the code short */ +static UA_StatusCode +readAttribute_simpleAsync(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, const UA_DataType *resultType, + UA_ClientAsyncOperationCallback callback, + void *userdata, UA_UInt32 *requestId) { + UA_ReadValueId rvi; + UA_ReadValueId_init(&rvi); + rvi.nodeId = *nodeId; + rvi.attributeId = attributeId; + return readAttribute_async(client, &rvi, UA_TIMESTAMPSTORETURN_NEITHER, + resultType, callback, userdata, requestId); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/client/ua_client_subscriptions.c" ***********************************/ +UA_StatusCode +UA_Client_readValueAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadValueAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_VALUE, + &UA_TYPES[UA_TYPES_DATAVALUE], /* special hndling */ + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readDataTypeAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDataTypeAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DATATYPE, + &UA_TYPES[UA_TYPES_NODEID], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readArrayDimensionsAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientReadArrayDimensionsAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, + &UA_TYPES[UA_TYPES_VARIANT], /* special handling */ + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readNodeClassAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadNodeClassAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_NODECLASS, + &UA_TYPES[UA_TYPES_NODECLASS], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readBrowseNameAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadBrowseNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME, + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readDisplayNameAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDisplayNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readDescriptionAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadDescriptionAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readWriteMaskAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadWriteMaskAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK, + &UA_TYPES[UA_TYPES_UINT32], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode UA_EXPORT +UA_Client_readUserWriteMaskAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserWriteMaskAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK, + &UA_TYPES[UA_TYPES_UINT32], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readIsAbstractAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadIsAbstractAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, + &UA_TYPES[UA_TYPES_BOOLEAN], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readSymmetricAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadSymmetricAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, + &UA_TYPES[UA_TYPES_BOOLEAN], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readInverseNameAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadInverseNameAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readContainsNoLoopsAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadContainsNoLoopsAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, + &UA_TYPES[UA_TYPES_BOOLEAN], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readEventNotifierAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadEventNotifierAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, + &UA_TYPES[UA_TYPES_BYTE], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readValueRankAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadValueRankAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_VALUERANK, + &UA_TYPES[UA_TYPES_INT32], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readAccessLevelAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadAccessLevelAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, + &UA_TYPES[UA_TYPES_BYTE], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readUserAccessLevelAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserAccessLevelAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL, + &UA_TYPES[UA_TYPES_BYTE], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readMinimumSamplingIntervalAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, + &UA_TYPES[UA_TYPES_DOUBLE], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readHistorizingAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadHistorizingAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING, + &UA_TYPES[UA_TYPES_BOOLEAN], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readExecutableAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadExecutableAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, + &UA_TYPES[UA_TYPES_BOOLEAN], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +UA_StatusCode +UA_Client_readUserExecutableAttribute_async(UA_Client *client, const UA_NodeId nodeId, + UA_ClientAsyncReadUserExecutableAttributeCallback callback, + void *userdata, UA_UInt32 *requestId) { + return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE, + &UA_TYPES[UA_TYPES_BOOLEAN], + (UA_ClientAsyncOperationCallback)callback, + userdata, requestId); +} + +/**** amalgamated original file "/src/client/ua_client_subscriptions.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -44691,21 +48814,12 @@ UA_Cient_translateBrowsePathsToNodeIds_async(UA_Client *client, char **paths, /*****************/ static void -UA_Client_MonitoredItem_remove(UA_Client *client, UA_Client_Subscription *sub, - UA_Client_MonitoredItem *mon); +MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub, + UA_Client_MonitoredItem *mon); static void -__Subscriptions_create_handler(UA_Client *client, void *data, UA_UInt32 requestId, void *r) { - UA_CreateSubscriptionResponse *response = (UA_CreateSubscriptionResponse *)r; - CustomCallback *cc = (CustomCallback *)data; - if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { - if(cc->clientData) - UA_free(cc->clientData); - goto cleanup; - } - - /* Prepare the internal representation */ - UA_Client_Subscription *newSub = (UA_Client_Subscription *)cc->clientData; +ua_Subscriptions_create(UA_Client *client, UA_Client_Subscription *newSub, + UA_CreateSubscriptionResponse *response) { newSub->subscriptionId = response->subscriptionId; newSub->sequenceNumber = 0; newSub->lastActivity = UA_DateTime_nowMonotonic(); @@ -44713,13 +48827,26 @@ __Subscriptions_create_handler(UA_Client *client, void *data, UA_UInt32 requestI newSub->maxKeepAliveCount = response->revisedMaxKeepAliveCount; LIST_INIT(&newSub->monitoredItems); LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry); +} -cleanup: - if(cc->isAsync) { - if(cc->userCallback) - cc->userCallback(client, cc->userData, requestId, response); - UA_free(cc); +static void +ua_Subscriptions_create_handler(UA_Client *client, void *data, UA_UInt32 requestId, + void *r) { + UA_CreateSubscriptionResponse *response = (UA_CreateSubscriptionResponse *)r; + CustomCallback *cc = (CustomCallback *)data; + UA_Client_Subscription *newSub = (UA_Client_Subscription *)cc->clientData; + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_free(newSub); + goto cleanup; } + + /* Prepare the internal representation */ + ua_Subscriptions_create(client, newSub, response); + +cleanup: + if(cc->userCallback) + cc->userCallback(client, cc->userData, requestId, response); + UA_free(cc); } UA_CreateSubscriptionResponse @@ -44729,48 +48856,39 @@ UA_Client_Subscriptions_create(UA_Client *client, UA_Client_StatusChangeNotificationCallback statusChangeCallback, UA_Client_DeleteSubscriptionCallback deleteCallback) { UA_CreateSubscriptionResponse response; - UA_CreateSubscriptionResponse_init(&response); - - CustomCallback cc; - memset(&cc, 0, sizeof(CustomCallback)); -#ifdef __clang_analyzer__ - cc.isAsync = false; -#endif - UA_Client_Subscription *sub = (UA_Client_Subscription *) UA_malloc(sizeof(UA_Client_Subscription)); if(!sub) { + UA_CreateSubscriptionResponse_init(&response); response.responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return response; } sub->context = subscriptionContext; sub->statusChangeCallback = statusChangeCallback; sub->deleteCallback = deleteCallback; - cc.clientData = sub; /* Send the request as a synchronous service call */ __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]); - __Subscriptions_create_handler(client, &cc, 0, &response); + ua_Subscriptions_create(client, sub, &response); return response; } UA_StatusCode -UA_Client_Subscriptions_create_async(UA_Client *client, const UA_CreateSubscriptionRequest request, +UA_Client_Subscriptions_create_async(UA_Client *client, + const UA_CreateSubscriptionRequest request, void *subscriptionContext, UA_Client_StatusChangeNotificationCallback statusChangeCallback, UA_Client_DeleteSubscriptionCallback deleteCallback, - UA_ClientAsyncServiceCallback createCallback, void *userdata, + UA_ClientAsyncServiceCallback createCallback, + void *userdata, UA_UInt32 *requestId) { CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback)); if(!cc) return UA_STATUSCODE_BADOUTOFMEMORY; - cc->isAsync = true; - cc->userCallback = createCallback; - cc->userData = userdata; UA_Client_Subscription *sub = (UA_Client_Subscription *) UA_malloc(sizeof(UA_Client_Subscription)); @@ -44781,14 +48899,16 @@ UA_Client_Subscriptions_create_async(UA_Client *client, const UA_CreateSubscript sub->context = subscriptionContext; sub->statusChangeCallback = statusChangeCallback; sub->deleteCallback = deleteCallback; + + cc->userCallback = createCallback; + cc->userData = userdata; cc->clientData = sub; /* Send the request as asynchronous service call */ - return __UA_Client_AsyncService(client, &request, - &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], - __Subscriptions_create_handler, - &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE], - cc, requestId); + return __UA_Client_AsyncService( + client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], + ua_Subscriptions_create_handler, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE], + cc, requestId); } static UA_Client_Subscription * @@ -44802,23 +48922,35 @@ findSubscription(const UA_Client *client, UA_UInt32 subscriptionId) { } static void -__Subscriptions_modify_handler(UA_Client *client, void *data, UA_UInt32 requestId, void *r) { - UA_ModifySubscriptionResponse *response = (UA_ModifySubscriptionResponse *)r; - CustomCallback *cc = (CustomCallback *)data; - UA_Client_Subscription *sub = (UA_Client_Subscription *)cc->clientData; - +ua_Subscriptions_modify(UA_Client *client, UA_Client_Subscription *sub, + const UA_ModifySubscriptionResponse *response) { sub->publishingInterval = response->revisedPublishingInterval; sub->maxKeepAliveCount = response->revisedMaxKeepAliveCount; +} - if(cc->isAsync) { - if(cc->userCallback) - cc->userCallback(client, cc->userData, requestId, response); - UA_free(cc); +static void +ua_Subscriptions_modify_handler(UA_Client *client, void *data, UA_UInt32 requestId, + void *r) { + UA_ModifySubscriptionResponse *response = (UA_ModifySubscriptionResponse *)r; + CustomCallback *cc = (CustomCallback *)data; + UA_Client_Subscription *sub = + findSubscription(client, (UA_UInt32)(uintptr_t)cc->clientData); + if(sub) { + ua_Subscriptions_modify(client, sub, response); + } else { + UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "No internal representation of subscription %" PRIu32, + (UA_UInt32)(uintptr_t)cc->clientData); } + + if(cc->userCallback) + cc->userCallback(client, cc->userData, requestId, response); + UA_free(cc); } UA_ModifySubscriptionResponse -UA_Client_Subscriptions_modify(UA_Client *client, const UA_ModifySubscriptionRequest request) { +UA_Client_Subscriptions_modify(UA_Client *client, + const UA_ModifySubscriptionRequest request) { UA_ModifySubscriptionResponse response; UA_ModifySubscriptionResponse_init(&response); @@ -44835,8 +48967,7 @@ UA_Client_Subscriptions_modify(UA_Client *client, const UA_ModifySubscriptionReq &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]); /* Adjust the internal representation */ - sub->publishingInterval = response.revisedPublishingInterval; - sub->maxKeepAliveCount = response.revisedMaxKeepAliveCount; + ua_Subscriptions_modify(client, sub, &response); return response; } @@ -44854,24 +48985,24 @@ UA_Client_Subscriptions_modify_async(UA_Client *client, if(!cc) return UA_STATUSCODE_BADOUTOFMEMORY; - cc->isAsync = true; - cc->clientData = sub; + cc->clientData = (void *)(uintptr_t)request.subscriptionId; cc->userData = userdata; cc->userCallback = callback; - return __UA_Client_AsyncService(client, &request, - &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], - __Subscriptions_modify_handler, - &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE], - cc, requestId); + return __UA_Client_AsyncService( + client, &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], + ua_Subscriptions_modify_handler, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE], + cc, requestId); } static void -UA_Client_Subscription_deleteInternal(UA_Client *client, UA_Client_Subscription *sub) { +UA_Client_Subscription_deleteInternal(UA_Client *client, + UA_Client_Subscription *sub) { /* Remove the MonitoredItems */ - UA_Client_MonitoredItem *mon, *mon_tmp; + UA_Client_MonitoredItem *mon; + UA_Client_MonitoredItem *mon_tmp; LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, mon_tmp) - UA_Client_MonitoredItem_remove(client, sub, mon); + MonitoredItem_delete(client, sub, mon); /* Call the delete callback */ if(sub->deleteCallback) @@ -44882,84 +49013,61 @@ UA_Client_Subscription_deleteInternal(UA_Client *client, UA_Client_Subscription UA_free(sub); } -typedef struct { - UA_DeleteSubscriptionsRequest *request; - UA_Client_Subscription **subs; -} Subscriptions_DeleteData; - static void -__Subscriptions_DeleteData_free(Subscriptions_DeleteData *data) { - if(!data) - return; - if(data->subs) - UA_free(data->subs); - if(data->request) - UA_delete(data->request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST]); - UA_free(data); -} - -static UA_INLINE void -__Subscriptions_delete_prepare(UA_Client *client, Subscriptions_DeleteData *data) { - /* temporary remove the subscriptions from the list */ - for(size_t i = 0; i < data->request->subscriptionIdsSize; i++) { - data->subs[i] = findSubscription(client, data->request->subscriptionIds[i]); - if(data->subs[i]) - LIST_REMOVE(data->subs[i], listEntry); - } -} - -static void -__Subscriptions_delete_handler(UA_Client *client, void *data, UA_UInt32 requestId, void *r) { - UA_DeleteSubscriptionsResponse *response = (UA_DeleteSubscriptionsResponse *)r; - CustomCallback *cc = (CustomCallback *)data; - Subscriptions_DeleteData *delData = (Subscriptions_DeleteData *)cc->clientData; - UA_DeleteSubscriptionsRequest *request = delData->request; - UA_Client_Subscription **subs = delData->subs; - +UA_Client_Subscription_processDelete(UA_Client *client, + const UA_DeleteSubscriptionsRequest *request, + const UA_DeleteSubscriptionsResponse *response) { if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) - goto cleanup; + return; - if(request->subscriptionIdsSize != response->resultsSize) { - response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; - goto cleanup; - } + /* Check that the request and response size -- use the same index for both */ + if(request->subscriptionIdsSize != response->resultsSize) + return; - /* Loop over the removed subscriptions and remove internally */ for(size_t i = 0; i < request->subscriptionIdsSize; i++) { if(response->results[i] != UA_STATUSCODE_GOOD && - response->results[i] != UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID) { - /* Something was wrong, reinsert the subscription in the list */ - if(subs[i]) - LIST_INSERT_HEAD(&client->subscriptions, subs[i], listEntry); + response->results[i] != UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID) continue; - } - if(!subs[i]) { + /* Get the Subscription */ + UA_Client_Subscription *sub = + findSubscription(client, request->subscriptionIds[i]); + if(!sub) { UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, "No internal representation of subscription %" PRIu32, - delData->request->subscriptionIds[i]); + request->subscriptionIds[i]); continue; } - LIST_INSERT_HEAD(&client->subscriptions, subs[i], listEntry); - UA_Client_Subscription_deleteInternal(client, subs[i]); + /* Delete the Subscription */ + UA_Client_Subscription_deleteInternal(client, sub); } -cleanup: - if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { - for(size_t i = 0; i < request->subscriptionIdsSize; i++) { - if(subs[i]) { - LIST_INSERT_HEAD(&client->subscriptions, subs[i], listEntry); - } - } - } +} - if(cc->isAsync) { - if(cc->userCallback) - cc->userCallback(client, cc->userData, requestId, response); - __Subscriptions_DeleteData_free(delData); - UA_free(cc); - } +typedef struct { + UA_DeleteSubscriptionsRequest request; + UA_ClientAsyncServiceCallback userCallback; + void *userData; +} DeleteSubscriptionCallback; + +static void +ua_Subscriptions_delete_handler(UA_Client *client, void *data, UA_UInt32 requestId, + void *r) { + UA_DeleteSubscriptionsResponse *response = + (UA_DeleteSubscriptionsResponse *)r; + DeleteSubscriptionCallback *dsc = + (DeleteSubscriptionCallback*)data; + + /* Delete */ + UA_Client_Subscription_processDelete(client, &dsc->request, response); + + /* Userland Callback */ + dsc->userCallback(client, dsc->userData, requestId, response); + + /* Cleanup */ + UA_DeleteSubscriptionsRequest_clear(&dsc->request); + UA_free(dsc); } UA_StatusCode @@ -44967,66 +49075,36 @@ UA_Client_Subscriptions_delete_async(UA_Client *client, const UA_DeleteSubscriptionsRequest request, UA_ClientAsyncServiceCallback callback, void *userdata, UA_UInt32 *requestId) { - CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback)); - if(!cc) + /* Make a copy of the request that persists into the async callback */ + DeleteSubscriptionCallback *dsc = + (DeleteSubscriptionCallback*)UA_malloc(sizeof(DeleteSubscriptionCallback)); + if(!dsc) return UA_STATUSCODE_BADOUTOFMEMORY; + dsc->userCallback = callback; + dsc->userData = userdata; + UA_StatusCode res = UA_DeleteSubscriptionsRequest_copy(&request, &dsc->request); + if(res != UA_STATUSCODE_GOOD) { + UA_free(dsc); + return res; + } - Subscriptions_DeleteData *data = (Subscriptions_DeleteData *) - UA_calloc(1, sizeof(Subscriptions_DeleteData)); - if(cc->clientData) - goto cleanup; - cc->clientData = data; - data->subs = (UA_Client_Subscription **) - UA_calloc(request.subscriptionIdsSize, sizeof(UA_Client_Subscription *)); - if(!data->subs) - goto cleanup; - - data->request = UA_DeleteSubscriptionsRequest_new(); - if(!data->request) - goto cleanup; - UA_DeleteSubscriptionsRequest_copy(&request, data->request); - - __Subscriptions_delete_prepare(client, data); - cc->isAsync = true; - cc->userCallback = callback; - cc->userData = userdata; - - return __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], - __Subscriptions_delete_handler, - &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE], - cc, requestId); -cleanup: - __Subscriptions_DeleteData_free(data); - UA_free(cc); - return UA_STATUSCODE_BADOUTOFMEMORY; + /* Make the async call */ + return __UA_Client_AsyncService( + client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], + ua_Subscriptions_delete_handler, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE], + dsc, requestId); } UA_DeleteSubscriptionsResponse UA_Client_Subscriptions_delete(UA_Client *client, const UA_DeleteSubscriptionsRequest request) { - UA_STACKARRAY(UA_Client_Subscription *, subs, request.subscriptionIdsSize); - memset(subs, 0, sizeof(void *) * request.subscriptionIdsSize); - - CustomCallback cc; - memset(&cc, 0, sizeof(CustomCallback)); -#ifdef __clang_analyzer__ - cc.isAsync = false; -#endif - - Subscriptions_DeleteData data; - cc.clientData = &data; - data.request = (UA_DeleteSubscriptionsRequest *)(uintptr_t)&request; - data.subs = subs; - - __Subscriptions_delete_prepare(client, &data); - /* Send the request */ UA_DeleteSubscriptionsResponse response; - __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]); - __Subscriptions_delete_handler(client, &cc, 0, &response); + /* Process */ + UA_Client_Subscription_processDelete(client, &request, &response); return response; } @@ -45042,17 +49120,17 @@ UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId UA_StatusCode retval = response.responseHeader.serviceResult; if(retval != UA_STATUSCODE_GOOD) { - UA_DeleteSubscriptionsResponse_deleteMembers(&response); + UA_DeleteSubscriptionsResponse_clear(&response); return retval; } if(response.resultsSize != 1) { - UA_DeleteSubscriptionsResponse_deleteMembers(&response); + UA_DeleteSubscriptionsResponse_clear(&response); return UA_STATUSCODE_BADINTERNALERROR; } retval = response.results[0]; - UA_DeleteSubscriptionsResponse_deleteMembers(&response); + UA_DeleteSubscriptionsResponse_clear(&response); return retval; } @@ -45061,9 +49139,8 @@ UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId /******************/ static void -UA_Client_MonitoredItem_remove(UA_Client *client, UA_Client_Subscription *sub, - UA_Client_MonitoredItem *mon) { - // NOLINTNEXTLINE +MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub, + UA_Client_MonitoredItem *mon) { LIST_REMOVE(mon, listEntry); if(mon->deleteCallback) mon->deleteCallback(client, sub->subscriptionId, sub->context, @@ -45072,129 +49149,155 @@ UA_Client_MonitoredItem_remove(UA_Client *client, UA_Client_Subscription *sub, } typedef struct { - UA_Client_Subscription *sub; - - UA_Client_MonitoredItem **mis; void **contexts; UA_Client_DeleteMonitoredItemCallback *deleteCallbacks; void **handlingCallbacks; + UA_CreateMonitoredItemsRequest request; - UA_CreateMonitoredItemsRequest *request; + /* Notify the user that the async callback was processed */ + UA_ClientAsyncServiceCallback userCallback; + void *userData; } MonitoredItems_CreateData; static void -MonitoredItems_CreateData_deleteItems(UA_Client_MonitoredItem **mis, - MonitoredItems_CreateData *data, UA_Client *client) { - bool hasCallbacks = (data->deleteCallbacks && data->contexts); - for(size_t i = 0; i < data->request->itemsToCreateSize; i++) { - if(!mis[i]) - continue; - UA_free(mis[i]); - mis[i] = NULL; - if(hasCallbacks && data->deleteCallbacks[i]) { - if(data->sub) - data->deleteCallbacks[i](client, data->sub->subscriptionId, - data->sub->context, 0, data->contexts[i]); - else - data->deleteCallbacks[i](client, 0, NULL, 0, data->contexts[i]); - } - } +MonitoredItems_CreateData_clear(UA_Client *client, MonitoredItems_CreateData *data) { + UA_free(data->contexts); + UA_free(data->deleteCallbacks); + UA_free(data->handlingCallbacks); + UA_CreateMonitoredItemsRequest_clear(&data->request); } static void -__MonitoredItems_create_handler(UA_Client *client, CustomCallback *cc, UA_UInt32 requestId, - UA_CreateMonitoredItemsResponse *response) { - MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)cc->clientData; - - // introduce local pointers to the variables/parameters in the CreateData - // to keep the code completely intact - UA_CreateMonitoredItemsRequest *request = data->request; +ua_MonitoredItems_create(UA_Client *client, MonitoredItems_CreateData *data, + UA_CreateMonitoredItemsResponse *response) { + UA_CreateMonitoredItemsRequest *request = &data->request; UA_Client_DeleteMonitoredItemCallback *deleteCallbacks = data->deleteCallbacks; - UA_Client_Subscription *sub = data->sub; - void **contexts = data->contexts; - UA_Client_MonitoredItem **mis = data->mis; - void **handlingCallbacks = data->handlingCallbacks; + + UA_Client_Subscription *sub = findSubscription(client, data->request.subscriptionId); + if(!sub) + goto cleanup; if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) - return; + goto cleanup; if(response->resultsSize != request->itemsToCreateSize) { response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; - return; + goto cleanup; } /* Add internally */ for(size_t i = 0; i < request->itemsToCreateSize; i++) { if(response->results[i].statusCode != UA_STATUSCODE_GOOD) { if(deleteCallbacks[i]) - deleteCallbacks[i](client, sub->subscriptionId, sub->context, 0, contexts[i]); - UA_free(mis[i]); - mis[i] = NULL; + deleteCallbacks[i](client, sub->subscriptionId, sub->context, + 0, data->contexts[i]); + continue; + } + + UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *) + UA_malloc(sizeof(UA_Client_MonitoredItem)); + if(!newMon) { + if(deleteCallbacks[i]) + deleteCallbacks[i](client, sub->subscriptionId, sub->context, 0, + data->contexts[i]); continue; } - UA_assert(mis[i] != NULL); - UA_Client_MonitoredItem *newMon = mis[i]; - newMon->clientHandle = request->itemsToCreate[i].requestedParameters.clientHandle; newMon->monitoredItemId = response->results[i].monitoredItemId; - newMon->context = contexts[i]; + newMon->clientHandle = request->itemsToCreate[i].requestedParameters.clientHandle; + newMon->context = data->contexts[i]; newMon->deleteCallback = deleteCallbacks[i]; newMon->handler.dataChangeCallback = - (UA_Client_DataChangeNotificationCallback)(uintptr_t)handlingCallbacks[i]; + (UA_Client_DataChangeNotificationCallback)(uintptr_t) + data->handlingCallbacks[i]; newMon->isEventMonitoredItem = - (request->itemsToCreate[i].itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER); + (request->itemsToCreate[i].itemToMonitor.attributeId == + UA_ATTRIBUTEID_EVENTNOTIFIER); LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry); UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Subscription %" PRIu32 " | Added a MonitoredItem with handle %" PRIu32, + "Subscription %" PRIu32 + " | Added a MonitoredItem with handle %" PRIu32, sub->subscriptionId, newMon->clientHandle); - mis[i] = NULL; + } + return; + + /* Adding failed */ + cleanup: + for(size_t i = 0; i < request->itemsToCreateSize; i++) { + if(deleteCallbacks[i]) + deleteCallbacks[i](client, data->request.subscriptionId, + sub ? sub->context : NULL, 0, data->contexts[i]); } } static void -__MonitoredItems_create_async_handler(UA_Client *client, void *d, - UA_UInt32 requestId, void *r) { +ua_MonitoredItems_create_async_handler(UA_Client *client, void *d, UA_UInt32 requestId, + void *r) { UA_CreateMonitoredItemsResponse *response = (UA_CreateMonitoredItemsResponse *)r; - CustomCallback *cc = (CustomCallback *)d; - MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)cc->clientData; + MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)d; - __MonitoredItems_create_handler(client, cc, requestId, response); - MonitoredItems_CreateData_deleteItems(data->mis, data, client); - if(cc->userCallback) - cc->userCallback(client, cc->userData, requestId, response); - UA_free(cc); - if(data->mis) - UA_free(data->mis); - if(data->request) - UA_CreateMonitoredItemsRequest_delete(data->request); + ua_MonitoredItems_create(client, data, response); + + if(data->userCallback) + data->userCallback(client, data->userData, requestId, response); + + MonitoredItems_CreateData_clear(client, data); UA_free(data); } static UA_StatusCode -MonitoredItems_CreateData_prepare(UA_Client_MonitoredItem **mis, - MonitoredItems_CreateData *data, UA_Client *client) { - /* Allocate the memory for internal representations */ - for(size_t i = 0; i < data->request->itemsToCreateSize; i++) { - mis[i] = (UA_Client_MonitoredItem *)UA_malloc(sizeof(UA_Client_MonitoredItem)); - if(!mis[i]) - return UA_STATUSCODE_BADOUTOFMEMORY; - } +MonitoredItems_CreateData_prepare(UA_Client *client, + const UA_CreateMonitoredItemsRequest *request, + void **contexts, void **handlingCallbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + MonitoredItems_CreateData *data) { + /* Align arrays and copy over */ + UA_StatusCode retval = UA_STATUSCODE_BADOUTOFMEMORY; + data->contexts = (void **)UA_calloc(request->itemsToCreateSize, sizeof(void *)); + if(!data->contexts) + goto cleanup; + if(contexts) + memcpy(data->contexts, contexts, request->itemsToCreateSize * sizeof(void *)); + + data->deleteCallbacks = (UA_Client_DeleteMonitoredItemCallback *) + UA_calloc(request->itemsToCreateSize, sizeof(UA_Client_DeleteMonitoredItemCallback)); + if(!data->deleteCallbacks) + goto cleanup; + if(deleteCallbacks) + memcpy(data->deleteCallbacks, deleteCallbacks, + request->itemsToCreateSize * sizeof(UA_Client_DeleteMonitoredItemCallback)); + + data->handlingCallbacks = (void **) + UA_calloc(request->itemsToCreateSize, sizeof(void *)); + if(!data->handlingCallbacks) + goto cleanup; + if(handlingCallbacks) + memcpy(data->handlingCallbacks, handlingCallbacks, + request->itemsToCreateSize * sizeof(void *)); + + retval = UA_CreateMonitoredItemsRequest_copy(request, &data->request); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; /* Set the clientHandle */ - for(size_t i = 0; i < data->request->itemsToCreateSize; i++) - data->request->itemsToCreate[i].requestedParameters.clientHandle = - ++(client->monitoredItemHandles); + for(size_t i = 0; i < data->request.itemsToCreateSize; i++) + data->request.itemsToCreate[i].requestedParameters.clientHandle = + ++client->monitoredItemHandles; return UA_STATUSCODE_GOOD; + +cleanup: + MonitoredItems_CreateData_clear(client, data); + return retval; } static void -__UA_Client_MonitoredItems_create(UA_Client *client, - const UA_CreateMonitoredItemsRequest *request, - void **contexts, void **handlingCallbacks, - UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, - UA_CreateMonitoredItemsResponse *response) { +ua_Client_MonitoredItems_create(UA_Client *client, + const UA_CreateMonitoredItemsRequest *request, + void **contexts, void **handlingCallbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + UA_CreateMonitoredItemsResponse *response) { UA_CreateMonitoredItemsResponse_init(response); if(!request->itemsToCreateSize) { @@ -45202,125 +49305,63 @@ __UA_Client_MonitoredItems_create(UA_Client *client, return; } - /* Get the subscription */ + /* Test if the subscription is valid */ UA_Client_Subscription *sub = findSubscription(client, request->subscriptionId); if(!sub) { response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; return; } - size_t itemsToCreateSize = request->itemsToCreateSize; - UA_STACKARRAY(UA_Client_MonitoredItem *, mis, itemsToCreateSize); - memset(mis, 0, sizeof(void *) * itemsToCreateSize); - MonitoredItems_CreateData data; memset(&data, 0, sizeof(MonitoredItems_CreateData)); - data.request = (UA_CreateMonitoredItemsRequest *)(uintptr_t)request; - data.contexts = contexts; - data.handlingCallbacks = handlingCallbacks; - data.deleteCallbacks = deleteCallbacks; - data.mis = mis; - data.sub = sub; - - CustomCallback cc; - memset(&cc, 0, sizeof(CustomCallback)); -#ifdef __clang_analyzer__ - cc.isAsync = false; -#endif - cc.clientData = &data; - UA_StatusCode retval = MonitoredItems_CreateData_prepare(mis, &data, client); - if(retval != UA_STATUSCODE_GOOD) { - response->responseHeader.serviceResult = retval; - MonitoredItems_CreateData_deleteItems(mis, &data, client); + UA_StatusCode res = + MonitoredItems_CreateData_prepare(client, request, contexts, handlingCallbacks, + deleteCallbacks, &data); + if(res != UA_STATUSCODE_GOOD) { + response->responseHeader.serviceResult = res; return; } - /* Call the service */ - __UA_Client_Service(client, request, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], + /* Call the service. Use data->request as it contains the client handle + * information. */ + __UA_Client_Service(client, &data.request, + &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]); - __MonitoredItems_create_handler(client, &cc, 0, response); - MonitoredItems_CreateData_deleteItems(mis, &data, client); + /* Add internal representation */ + ua_MonitoredItems_create(client, &data, response); - for(size_t i = 0; i < itemsToCreateSize; i++) - UA_assert(mis[i] == NULL); + MonitoredItems_CreateData_clear(client, &data); } static UA_StatusCode -__UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client, - const UA_CreateMonitoredItemsRequest request, - void **contexts, void **callbacks, - UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, - UA_ClientAsyncServiceCallback createCallback, - void *userdata, UA_UInt32 *requestId) { +ua_Client_MonitoredItems_createDataChanges_async( + UA_Client *client, const UA_CreateMonitoredItemsRequest request, void **contexts, + void **callbacks, UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, + UA_ClientAsyncServiceCallback createCallback, void *userdata, UA_UInt32 *requestId) { UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); if(!sub) return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; - CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback)); - if(!cc) - return UA_STATUSCODE_BADOUTOFMEMORY; - MonitoredItems_CreateData *data = (MonitoredItems_CreateData *) UA_calloc(1, sizeof(MonitoredItems_CreateData)); - if(!data) { - UA_free(cc); + if(!data) return UA_STATUSCODE_BADOUTOFMEMORY; - } + data->userCallback = createCallback; + data->userData = userdata; - data->sub = sub; - cc->userCallback = createCallback; - cc->userData = userdata; - cc->isAsync = true; - cc->clientData = data; - - /* Create a big array that holds the monitored items and parameters */ - UA_StatusCode retval = UA_STATUSCODE_GOOD; - void **array = (void **)UA_calloc(4 * request.itemsToCreateSize, sizeof(void *)); - if(!array) { - retval = UA_STATUSCODE_BADOUTOFMEMORY; - goto cleanup; - } - data->mis = (UA_Client_MonitoredItem **)array; - data->contexts = (void **) - ((uintptr_t)array + (sizeof(void *) * request.itemsToCreateSize)); - memcpy(data->contexts, contexts, request.itemsToCreateSize * sizeof(void *)); - data->deleteCallbacks = (UA_Client_DeleteMonitoredItemCallback *) - ((uintptr_t)array + (2 * request.itemsToCreateSize * sizeof(void *))); - memcpy(data->deleteCallbacks, deleteCallbacks, - request.itemsToCreateSize * sizeof(UA_Client_DeleteMonitoredItemCallback)); - data->handlingCallbacks = (void **) - ((uintptr_t)array + (3 * request.itemsToCreateSize * sizeof(void *))); - memcpy(data->handlingCallbacks, callbacks, request.itemsToCreateSize * sizeof(void *)); - - data->request = UA_CreateMonitoredItemsRequest_new(); - if(!data->request) { - retval = UA_STATUSCODE_BADOUTOFMEMORY; - goto cleanup; + UA_StatusCode res = MonitoredItems_CreateData_prepare( + client, &request, contexts, callbacks, deleteCallbacks, data); + if(res != UA_STATUSCODE_GOOD) { + UA_free(data); + return res; } - retval = UA_CreateMonitoredItemsRequest_copy(&request, data->request); - if(retval != UA_STATUSCODE_GOOD) - goto cleanup; - - retval = MonitoredItems_CreateData_prepare(data->mis, data, client); - if(retval != UA_STATUSCODE_GOOD) - goto cleanup; - return __UA_Client_AsyncService(client, data->request, - &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], - __MonitoredItems_create_async_handler, - &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE], - cc, requestId); -cleanup: - MonitoredItems_CreateData_deleteItems(data->mis, data, client); - if(data->mis) - UA_free(data->mis); - if(data->request) - UA_CreateMonitoredItemsRequest_delete(data->request); - UA_free(data); - UA_free(cc); - return retval; + return __UA_Client_AsyncService( + client, &data->request, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], + ua_MonitoredItems_create_async_handler, + &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE], data, requestId); } UA_CreateMonitoredItemsResponse @@ -45330,8 +49371,8 @@ UA_Client_MonitoredItems_createDataChanges(UA_Client *client, UA_Client_DataChangeNotificationCallback *callbacks, UA_Client_DeleteMonitoredItemCallback *deleteCallbacks) { UA_CreateMonitoredItemsResponse response; - __UA_Client_MonitoredItems_create(client, &request, contexts, - (void**)(uintptr_t)callbacks, deleteCallbacks, &response); + ua_Client_MonitoredItems_create(client, &request, contexts, (void **)callbacks, + deleteCallbacks, &response); return response; } @@ -45343,16 +49384,16 @@ UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client, UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, UA_ClientAsyncServiceCallback createCallback, void *userdata, UA_UInt32 *requestId) { - return __UA_Client_MonitoredItems_createDataChanges_async(client, request, contexts, - (void **)(uintptr_t)callbacks, - deleteCallbacks, createCallback, - userdata, requestId); + return ua_Client_MonitoredItems_createDataChanges_async( + client, request, contexts, (void **)callbacks, deleteCallbacks, createCallback, + userdata, requestId); } UA_MonitoredItemCreateResult UA_Client_MonitoredItems_createDataChange(UA_Client *client, UA_UInt32 subscriptionId, UA_TimestampsToReturn timestampsToReturn, - const UA_MonitoredItemCreateRequest item, void *context, + const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_DataChangeNotificationCallback callback, UA_Client_DeleteMonitoredItemCallback deleteCallback) { UA_CreateMonitoredItemsRequest request; @@ -45375,17 +49416,19 @@ UA_Client_MonitoredItems_createDataChange(UA_Client *client, UA_UInt32 subscript if(result.statusCode == UA_STATUSCODE_GOOD) UA_MonitoredItemCreateResult_copy(&response.results[0] , &result); - UA_CreateMonitoredItemsResponse_deleteMembers(&response); + UA_CreateMonitoredItemsResponse_clear(&response); return result; } UA_CreateMonitoredItemsResponse -UA_Client_MonitoredItems_createEvents(UA_Client *client, const UA_CreateMonitoredItemsRequest request, - void **contexts, UA_Client_EventNotificationCallback *callback, +UA_Client_MonitoredItems_createEvents(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, + void **contexts, + UA_Client_EventNotificationCallback *callback, UA_Client_DeleteMonitoredItemCallback *deleteCallback) { UA_CreateMonitoredItemsResponse response; - __UA_Client_MonitoredItems_create(client, &request, contexts, - (void**)(uintptr_t)callback, deleteCallback, &response); + ua_Client_MonitoredItems_create(client, &request, contexts, (void **)callback, + deleteCallback, &response); return response; } @@ -45398,10 +49441,9 @@ UA_Client_MonitoredItems_createEvents_async(UA_Client *client, UA_Client_DeleteMonitoredItemCallback *deleteCallbacks, UA_ClientAsyncServiceCallback createCallback, void *userdata, UA_UInt32 *requestId) { - return __UA_Client_MonitoredItems_createDataChanges_async(client, request, contexts, - (void **)(uintptr_t)callbacks, - deleteCallbacks, createCallback, - userdata, requestId); + return ua_Client_MonitoredItems_createDataChanges_async( + client, request, contexts, (void **)callbacks, deleteCallbacks, createCallback, + userdata, requestId); } UA_MonitoredItemCreateResult @@ -45423,31 +49465,22 @@ UA_Client_MonitoredItems_createEvent(UA_Client *client, UA_UInt32 subscriptionId UA_MonitoredItemCreateResult result; UA_MonitoredItemCreateResult_init(&result); if(retval != UA_STATUSCODE_GOOD) { - UA_CreateMonitoredItemsResponse_deleteMembers(&response); + UA_CreateMonitoredItemsResponse_clear(&response); result.statusCode = retval; return result; } UA_MonitoredItemCreateResult_copy(response.results , &result); - UA_CreateMonitoredItemsResponse_deleteMembers(&response); + UA_CreateMonitoredItemsResponse_clear(&response); return result; } static void -__MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId, void *r) { - UA_DeleteMonitoredItemsResponse *response = (UA_DeleteMonitoredItemsResponse *)r; - CustomCallback *cc = (CustomCallback *)d; - UA_DeleteMonitoredItemsRequest *request = - (UA_DeleteMonitoredItemsRequest *)cc->clientData; - if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) - goto cleanup; - - UA_Client_Subscription *sub = findSubscription(client, request->subscriptionId); - if(!sub) { - UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "No internal representation of subscription %" PRIu32, - request->subscriptionId); - goto cleanup; - } +ua_MonitoredItems_delete(UA_Client *client, UA_Client_Subscription *sub, + const UA_DeleteMonitoredItemsRequest *request, + const UA_DeleteMonitoredItemsResponse *response) { +#ifdef __clang_analyzer__ + return; +#endif /* Loop over deleted MonitoredItems */ for(size_t i = 0; i < response->resultsSize; i++) { @@ -45456,25 +49489,43 @@ __MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId, continue; } -#ifndef __clang_analyzer__ /* Delete the internal representation */ UA_Client_MonitoredItem *mon; LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { - // NOLINTNEXTLINE if(mon->monitoredItemId == request->monitoredItemIds[i]) { - UA_Client_MonitoredItem_remove(client, sub, mon); + MonitoredItem_delete(client, sub, mon); break; } } -#endif } -cleanup: - if(cc->isAsync) { - if(cc->userCallback) - cc->userCallback(client, cc->userData, requestId, response); - UA_DeleteMonitoredItemsRequest_delete(request); - UA_free(cc); +} + +static void +ua_MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId, + void *r) { + CustomCallback *cc = (CustomCallback *)d; + UA_DeleteMonitoredItemsResponse *response = (UA_DeleteMonitoredItemsResponse *)r; + UA_DeleteMonitoredItemsRequest *request = + (UA_DeleteMonitoredItemsRequest *)cc->clientData; + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) + goto cleanup; + + UA_Client_Subscription *sub = findSubscription(client, request->subscriptionId); + if(!sub) { + UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "No internal representation of subscription %" PRIu32, + request->subscriptionId); + goto cleanup; } + + /* Delete MonitoredItems from the internal representation */ + ua_MonitoredItems_delete(client, sub, request, response); + +cleanup: + if(cc->userCallback) + cc->userCallback(client, cc->userData, requestId, response); + UA_DeleteMonitoredItemsRequest_delete(request); + UA_free(cc); } UA_DeleteMonitoredItemsResponse @@ -45482,17 +49533,24 @@ UA_Client_MonitoredItems_delete(UA_Client *client, const UA_DeleteMonitoredItemsRequest request) { /* Send the request */ UA_DeleteMonitoredItemsResponse response; - CustomCallback cc; - memset(&cc, 0, sizeof(CustomCallback)); -#ifdef __clang_analyzer__ - cc.isAsync = false; -#endif - cc.clientData = (void *)(uintptr_t)&request; - __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]); - __MonitoredItems_delete_handler(client, &cc, 0, &response); + /* A problem occured remote? */ + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) + return response; + + /* Find the internal subscription representation */ + UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + if(!sub) { + UA_LOG_INFO(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "No internal representation of subscription %" PRIu32, + request.subscriptionId); + return response; + } + + /* Remove MonitoredItems in the internal representation */ + ua_MonitoredItems_delete(client, sub, &request, &response); return response; } @@ -45511,16 +49569,16 @@ UA_Client_MonitoredItems_delete_async(UA_Client *client, UA_free(cc); return UA_STATUSCODE_BADOUTOFMEMORY; } + UA_DeleteMonitoredItemsRequest_copy(&request, req_copy); - cc->isAsync = true; cc->clientData = req_copy; cc->userCallback = callback; cc->userData = userdata; return __UA_Client_AsyncService( client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], - __MonitoredItems_delete_handler, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE], - cc, requestId); + ua_MonitoredItems_delete_handler, + &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE], cc, requestId); } UA_StatusCode @@ -45537,17 +49595,17 @@ UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionI UA_StatusCode retval = response.responseHeader.serviceResult; if(retval != UA_STATUSCODE_GOOD) { - UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + UA_DeleteMonitoredItemsResponse_clear(&response); return retval; } if(response.resultsSize != 1) { - UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + UA_DeleteMonitoredItemsResponse_clear(&response); return UA_STATUSCODE_BADINTERNALERROR; } retval = response.results[0]; - UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + UA_DeleteMonitoredItemsResponse_clear(&response); return retval; } @@ -45556,7 +49614,7 @@ UA_Client_MonitoredItems_modify(UA_Client *client, const UA_ModifyMonitoredItemsRequest request) { UA_ModifyMonitoredItemsResponse response; - UA_Client_Subscription *sub = 0; + UA_Client_Subscription *sub; LIST_FOREACH(sub, &client->subscriptions, listEntry) { if (sub->subscriptionId == request.subscriptionId) break; @@ -45572,7 +49630,7 @@ UA_Client_MonitoredItems_modify(UA_Client *client, UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest); for (size_t i = 0; i < modifiedRequest.itemsToModifySize; ++i) { - UA_Client_MonitoredItem *mon = 0; + UA_Client_MonitoredItem *mon; LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { if(mon->monitoredItemId == modifiedRequest.itemsToModify[i].monitoredItemId) { modifiedRequest.itemsToModify[i].requestedParameters.clientHandle = mon->clientHandle; @@ -45585,7 +49643,7 @@ UA_Client_MonitoredItems_modify(UA_Client *client, &modifiedRequest, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], &response, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]); - UA_ModifyMonitoredItemsRequest_deleteMembers(&modifiedRequest); + UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest); return response; } @@ -45646,22 +49704,24 @@ processDataChangeNotification(UA_Client *client, UA_Client_Subscription *sub, } if(!mon) { - UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Could not process a notification with clienthandle %" PRIu32 - " on subscription %" PRIu32, min->clientHandle, sub->subscriptionId); + UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "Could not process a notification with clienthandle %" PRIu32 + " on subscription %" PRIu32, min->clientHandle, sub->subscriptionId); continue; } if(mon->isEventMonitoredItem) { - UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "MonitoredItem is configured for Events. But received a " - "DataChangeNotification."); + UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, + "MonitoredItem is configured for Events. But received a " + "DataChangeNotification."); continue; } - mon->handler.dataChangeCallback(client, sub->subscriptionId, sub->context, - mon->monitoredItemId, mon->context, - &min->value); + if(mon->handler.dataChangeCallback) { + mon->handler.dataChangeCallback(client, sub->subscriptionId, sub->context, + mon->monitoredItemId, mon->context, + &min->value); + } } } @@ -45729,7 +49789,8 @@ processNotificationMessage(UA_Client *client, UA_Client_Subscription *sub, (UA_StatusChangeNotification*)msg->content.decoded.data); } else { UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Dropped a StatusChangeNotification since no callback is registered"); + "Dropped a StatusChangeNotification since no " + "callback is registered"); } return; } @@ -45749,8 +49810,8 @@ UA_Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequ if(client->config.outStandingPublishRequests > 1) { client->config.outStandingPublishRequests--; UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Too many publishrequest, reduce outStandingPublishRequests to %" PRId16, - client->config.outStandingPublishRequests); + "Too many publishrequest, reduce outStandingPublishRequests " + "to %" PRId16, client->config.outStandingPublishRequests); } else { UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Too many publishrequest when outStandingPublishRequests = 1"); @@ -45771,7 +49832,7 @@ UA_Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequ if(client->sessionState != UA_SESSIONSTATE_ACTIVATED) { UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Received Publish Response with code %s", - UA_StatusCode_name(response->responseHeader.serviceResult)); + UA_StatusCode_name(response->responseHeader.serviceResult)); UA_Client_Subscription* sub = findSubscription(client, response->subscriptionId); if (sub != NULL) UA_Client_Subscription_deleteInternal(client, sub); @@ -45787,8 +49848,12 @@ UA_Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequ } if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTIMEOUT) { - if (client->config.inactivityCallback) - client->config.inactivityCallback(client); + if (client->config.subscriptionInactivityCallback) { + UA_Client_Subscription* sub = findSubscription(client, response->subscriptionId); + if (sub != NULL) + client->config.subscriptionInactivityCallback(client, sub->subscriptionId, + sub->context); + } UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Received Timeout for Publish Response"); return; @@ -45814,19 +49879,20 @@ UA_Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequ /* Detect missing message - OPC Unified Architecture, Part 4 5.13.1.1 e) */ if(UA_Client_Subscriptions_nextSequenceNumber(sub->sequenceNumber) != msg->sequenceNumber) { UA_LOG_WARNING(&client->config.logger, UA_LOGCATEGORY_CLIENT, - "Invalid subscription sequence number: expected %" PRIu32 " but got %" PRIu32, - UA_Client_Subscriptions_nextSequenceNumber(sub->sequenceNumber), - msg->sequenceNumber); + "Invalid subscription sequence number: expected %" PRIu32 + " but got %" PRIu32, + UA_Client_Subscriptions_nextSequenceNumber(sub->sequenceNumber), + msg->sequenceNumber); /* This is an error. But we do not abort the connection. Some server * SDKs misbehave from time to time and send out-of-order sequence * numbers. (Probably some multi-threading synchronization issue.) */ /* UA_Client_disconnect(client); return; */ } - /* According to f), a keep-alive message contains no notifications and has the sequence number - * of the next NotificationMessage that is to be sent => More than one consecutive keep-alive - * message or a NotificationMessage following a keep-alive message will share the same sequence - * number. */ + /* According to f), a keep-alive message contains no notifications and has + * the sequence number of the next NotificationMessage that is to be sent => + * More than one consecutive keep-alive message or a NotificationMessage + * following a keep-alive message will share the same sequence number. */ if (msg->notificationDataSize) sub->sequenceNumber = msg->sequenceNumber; @@ -45854,8 +49920,8 @@ UA_Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequ } static void -processPublishResponseAsync(UA_Client *client, void *userdata, UA_UInt32 requestId, - void *response) { +processPublishResponseAsync(UA_Client *client, void *userdata, + UA_UInt32 requestId, void *response) { UA_PublishRequest *req = (UA_PublishRequest*)userdata; UA_PublishResponse *res = (UA_PublishResponse*)response; @@ -45871,13 +49937,15 @@ processPublishResponseAsync(UA_Client *client, void *userdata, UA_UInt32 request void UA_Client_Subscriptions_clean(UA_Client *client) { - UA_Client_NotificationsAckNumber *n, *tmp; + UA_Client_NotificationsAckNumber *n; + UA_Client_NotificationsAckNumber *tmp; LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) { LIST_REMOVE(n, listEntry); UA_free(n); } - UA_Client_Subscription *sub, *tmps; + UA_Client_Subscription *sub; + UA_Client_Subscription *tmps; LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps) UA_Client_Subscription_deleteInternal(client, sub); /* force local removal */ @@ -45937,7 +50005,8 @@ UA_Client_Subscriptions_backgroundPublish(UA_Client *client) { /* Disable the timeout, it is treat in * UA_Client_Subscriptions_backgroundPublishInactivityCheck */ - retval = __UA_Client_AsyncServiceEx(client, request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST], + retval = __UA_Client_AsyncServiceEx(client, request, + &UA_TYPES[UA_TYPES_PUBLISHREQUEST], processPublishResponseAsync, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], (void*)request, &requestId, 0); @@ -45950,7 +50019,7 @@ UA_Client_Subscriptions_backgroundPublish(UA_Client *client) { #endif /* UA_ENABLE_SUBSCRIPTIONS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/libc_time.c" ***********************************/ +/**** amalgamated original file "/deps/libc_time.c" ****/ /* Originally released by the musl project (http://www.musl-libc.org/) under the * MIT license. Taken from the file /src/time/__secs_to_tm.c */ @@ -46099,7 +50168,7 @@ long long __tm_to_secs(const struct mytm *tm) { return t; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/pcg_basic.c" ***********************************/ +/**** amalgamated original file "/deps/pcg_basic.c" ****/ /* * PCG Random Number Generation for C. @@ -46141,7 +50210,7 @@ uint32_t pcg32_random_r(pcg32_random_t* rng) { return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31)); /* was (xorshifted >> rot) | (xorshifted << ((-rot) & 31)) */ } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/deps/base64.c" ***********************************/ +/**** amalgamated original file "/deps/base64.c" ****/ /* * Base64 encoding: Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> @@ -46257,7 +50326,1644 @@ UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { return str; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/build/src_generated/open62541/namespace0_generated.c" ***********************************/ +/**** amalgamated original file "/deps/aa_tree.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + +#include <stddef.h> + +#if !defined(_MSC_VER) || _MSC_VER >= 1800 +# include <inttypes.h> +#elif !defined(uintptr_t) + /* Workaround missing standard includes in older Visual Studio */ +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +typedef _W64 unsigned int uintptr_t; +# else +typedef unsigned __int64 uintptr_t; +# endif +#endif + +#define aa_entry_container(head, entry) \ + ((void*)((uintptr_t)entry - head->entry_offset)) +#define aa_entry_key(head, entry) \ + ((const void*)((uintptr_t)entry + head->key_offset - head->entry_offset)) +#define aa_container_entry(head, container) \ + ((struct aa_entry*)((uintptr_t)container + head->entry_offset)) +#define aa_container_key(head, container) \ + ((const void*)((uintptr_t)container + head->key_offset)) + +void +aa_init(struct aa_head *head, + enum aa_cmp (*cmp)(const void*, const void*), + unsigned int entry_offset, unsigned int key_offset) { + head->root = NULL; + head->cmp = cmp; + head->entry_offset = entry_offset; + head->key_offset = key_offset; +} + +static struct aa_entry * +_aa_skew(struct aa_entry *n) { + if(!n) + return NULL; + if(n->left && n->level == n->left->level) { + struct aa_entry *l = n->left; + n->left = l->right; + l->right = n; + return l; + } + return n; +} + +static struct aa_entry * +_aa_split(struct aa_entry *n) { + if(!n) + return NULL; + if(n->right && n->right->right && + n->right->right->level == n->level) { + struct aa_entry *r = n->right; + n->right = r->left; + r->left = n; + r->level++; + return r; + } + return n; +} + +static struct aa_entry * +_aa_fixup(struct aa_entry *n) { + unsigned int should_be = 0; + if(n->left) + should_be = n->left->level; + if(n->right && n->right->level < should_be) + should_be = n->right->level; + should_be++; + if(should_be < n->level) + n->level = should_be; + if(n->right && n->right->level > should_be) + n->right->level = should_be; + n = _aa_skew(n); + n->right = _aa_skew(n->right); + if(n->right) + n->right->right = _aa_skew(n->right->right); + n = _aa_split(n); + n->right = _aa_split(n->right); + return n; +} + +static struct aa_entry * +_aa_insert(struct aa_head *h, struct aa_entry *n, void *elem) { + if(!n) { + struct aa_entry *e = aa_container_entry(h, elem); + e->left = NULL; + e->right = NULL; + e->level = 1; + return e; + } + const void *n_key = aa_entry_key(h, n); + const void *key = aa_container_key(h, elem); + enum aa_cmp eq = h->cmp(key, n_key); + if(eq == AA_CMP_EQ) + eq = (key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; + if(eq == AA_CMP_LESS) + n->left = _aa_insert(h, n->left, elem); + else + n->right = _aa_insert(h, n->right, elem); + return _aa_split(_aa_skew(n)); +} + +void +aa_insert(struct aa_head *h, void *elem) { + h->root = _aa_insert(h, h->root, elem); +} + +void * +aa_find(const struct aa_head *h, const void *key) { + struct aa_entry *n = h->root; + while(n) { + enum aa_cmp eq = h->cmp(key, aa_entry_key(h, n)); + if(eq == AA_CMP_EQ) + return aa_entry_container(h, n); + n = (eq == AA_CMP_LESS) ? n->left : n->right; + } + return NULL; +} + +static struct aa_entry * +unlink_succ(struct aa_entry *n, struct aa_entry **succ) { + if(!n->left) { + *succ = n; + return n->right; + } + n->left = unlink_succ(n->left, succ); + return _aa_fixup(n); +} + +static struct aa_entry * +unlink_pred(struct aa_entry *n, struct aa_entry **pred) { + if(!n->right) { + *pred = n; + return n->left; + } + n->right = unlink_pred(n->right, pred); + return _aa_fixup(n); +} + +static struct aa_entry * +_aa_remove(struct aa_head *h, void *elem, struct aa_entry *n) { + if(!n) + return NULL; + + const void *elem_key = aa_container_key(h, elem); + const void *n_key = aa_entry_key(h, n); + if(n_key == elem_key) { + if(!n->left && !n->right) + return NULL; + struct aa_entry *replace = NULL; + if(!n->left) + n->right = unlink_succ(n->right, &replace); + else + n->left = unlink_pred(n->left, &replace); + replace->left = n->left; + replace->right = n->right; + replace->level = n->level; + return _aa_fixup(replace); + } + + enum aa_cmp eq = h->cmp(elem_key, n_key); + if(eq == AA_CMP_EQ) + eq = (elem_key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; + if(eq == AA_CMP_LESS) + n->left = _aa_remove(h, elem, n->left); + else + n->right = _aa_remove(h, elem, n->right); + return _aa_fixup(n); +} + +void +aa_remove(struct aa_head *head, void *elem) { + head->root = _aa_remove(head, elem, head->root); +} + +void * +aa_min(const struct aa_head *head) { + struct aa_entry *e = head->root; + if(!e) + return NULL; + while(e->left) + e = e->left; + return aa_entry_container(head, e); +} + +void * +aa_max(const struct aa_head *head) { + struct aa_entry *e = head->root; + if(!e) + return NULL; + while(e->right) + e = e->right; + return aa_entry_container(head, e); +} + +void * +aa_next(const struct aa_head *head, const void *elem) { + struct aa_entry *e = aa_container_entry(head, elem); + if(e->right) { + e = e->right; + while(e->left) + e = e->left; + return aa_entry_container(head, e); + } + struct aa_entry *next = NULL; + struct aa_entry *n = head->root; + const void *key = aa_container_key(head, elem); + while(n && n != e) { + const void *n_key = aa_entry_key(head, n); + enum aa_cmp eq = head->cmp(key, n_key); + if(eq == AA_CMP_EQ) + eq = (key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; + if(eq == AA_CMP_MORE) { + n = n->right; + } else { + next = n; + n = n->left; + } + } + return (next) ? aa_entry_container(head, next) : NULL; +} + +void * +aa_prev(const struct aa_head *head, const void *elem) { + struct aa_entry *e = aa_container_entry(head, elem); + if(e->left) { + e = e->left; + while(e->right) + e = e->right; + return aa_entry_container(head, e); + } + struct aa_entry *prev = NULL; + struct aa_entry *n = head->root; + const void *key = aa_container_key(head, elem); + while(n && n != e) { + const void *n_key = aa_entry_key(head, n); + enum aa_cmp eq = head->cmp(key, n_key); + if(eq == AA_CMP_EQ) + eq = (key > n_key) ? AA_CMP_MORE : AA_CMP_LESS; + if(eq == AA_CMP_MORE) { + prev = n; + n = n->right; + } else { + n = n->left; + } + } + return (prev) ? aa_entry_container(head, prev) : NULL; +} + +/**** amalgamated original file "/deps/ziptree.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2021 (c) Julius Pfrommer + */ + + +#if defined(_MSC_VER) +#include <intrin.h> +#endif + +unsigned char +__ZIP_FFS32(unsigned int v) { +#if defined(__GNUC__) || defined(__clang__) + return (unsigned char)((unsigned char)__builtin_ffs((int)v) - 1u); +#elif defined(_MSC_VER) + unsigned long index = 255; + _BitScanForward(&index, v); + return (unsigned char)index; +#else + if(v == 0) + return 255; + unsigned int t = 1; + unsigned char r = 0; + while((v & t) == 0) { + t = t << 1; + r++; + } + return r; +#endif +} + +/* Generic analog to ZIP_ENTRY(type) */ +struct zip_entry { + void *left; + void *right; + unsigned char rank; +}; + +#define ZIP_ENTRY_PTR(x) (struct zip_entry*)((char*)x + fieldoffset) +#define ZIP_KEY_PTR(x) (void*)((char*)x + keyoffset) + +void * +__ZIP_INSERT(zip_cmp_cb cmp, unsigned short fieldoffset, + unsigned short keyoffset, void *root, void *elm) { + struct zip_entry *root_entry = ZIP_ENTRY_PTR(root); + struct zip_entry *elm_entry = ZIP_ENTRY_PTR(elm); + if(!root) { + elm_entry->left = NULL; + elm_entry->right = NULL; + return elm; + } + enum ZIP_CMP order = cmp(ZIP_KEY_PTR(elm), ZIP_KEY_PTR(root)); + if(order == ZIP_CMP_LESS) { + if(__ZIP_INSERT(cmp, fieldoffset, keyoffset, root_entry->left, elm) == elm) { + if(elm_entry->rank < root_entry->rank) { + root_entry->left = elm; + } else { + root_entry->left = elm_entry->right; + elm_entry->right = root; + return elm; + } + } + } else { + if(__ZIP_INSERT(cmp, fieldoffset, keyoffset, root_entry->right, elm) == elm) { + if(elm_entry->rank <= root_entry->rank) { + root_entry->right = elm; + } else { + root_entry->right = elm_entry->left; + elm_entry->left = root; + return elm; + } + } + } + return root; +} + +static void * +__ZIP(unsigned short fieldoffset, void *x, void *y) { + if(!x) return y; + if(!y) return x; + struct zip_entry *x_entry = ZIP_ENTRY_PTR(x); + struct zip_entry *y_entry = ZIP_ENTRY_PTR(y); + if(x_entry->rank < y_entry->rank) { + y_entry->left = __ZIP(fieldoffset, x, y_entry->left); + return y; + } else { + x_entry->right = __ZIP(fieldoffset, x_entry->right, y); + return x; + } +} + +/* Modified from the original algorithm. Allow multiple elements with the same + * key. */ +void * +__ZIP_REMOVE(zip_cmp_cb cmp, unsigned short fieldoffset, + unsigned short keyoffset, void *root, void *elm) { + struct zip_entry *root_entry = ZIP_ENTRY_PTR(root); + if(root == elm) + return __ZIP(fieldoffset, root_entry->left, root_entry->right); + void *left = root_entry->left; + void *right = root_entry->right; + enum ZIP_CMP eq = cmp(ZIP_KEY_PTR(elm), ZIP_KEY_PTR(root)); + if(eq == ZIP_CMP_LESS) { + struct zip_entry *left_entry = ZIP_ENTRY_PTR(left); + if(elm == left) + root_entry->left = __ZIP(fieldoffset, left_entry->left, left_entry->right); + else if(left) + __ZIP_REMOVE(cmp, fieldoffset, keyoffset, left, elm); + } else if(eq == ZIP_CMP_MORE) { + struct zip_entry *right_entry = ZIP_ENTRY_PTR(right); + if(elm == right) + root_entry->right = __ZIP(fieldoffset, right_entry->left, right_entry->right); + else if(right) + __ZIP_REMOVE(cmp, fieldoffset, keyoffset, right, elm); + } else { /* ZIP_CMP_EQ, but root != elm */ + if(right) + root_entry->right = __ZIP_REMOVE(cmp, fieldoffset, keyoffset, right, elm); + if(left) + root_entry->left = __ZIP_REMOVE(cmp, fieldoffset, keyoffset, left, elm); + } + return root; +} + +void * +__ZIP_FIND(zip_cmp_cb cmp, unsigned short fieldoffset, + unsigned short keyoffset, void *root, const void *key) { + if(!root) + return NULL; + enum ZIP_CMP eq = cmp(key, ZIP_KEY_PTR(root)); + if(eq == ZIP_CMP_EQ) + return root; + struct zip_entry *root_entry = ZIP_ENTRY_PTR(root); + if(eq == ZIP_CMP_LESS) + return __ZIP_FIND(cmp, fieldoffset, keyoffset, root_entry->left, key); + else + return __ZIP_FIND(cmp, fieldoffset, keyoffset, root_entry->right, key); +} + +void * +__ZIP_MIN(unsigned short fieldoffset, void *elm) { + if(!elm) + return NULL; + struct zip_entry *elm_entry = ZIP_ENTRY_PTR(elm); + while(elm_entry->left) { + elm = elm_entry->left; + elm_entry = (struct zip_entry*)((char*)elm + fieldoffset); + } + return elm; +} + +void * +__ZIP_MAX(unsigned short fieldoffset, void *elm) { + if(!elm) + return NULL; + struct zip_entry *elm_entry = ZIP_ENTRY_PTR(elm); + while(elm_entry->right) { + elm = elm_entry->right; + elm_entry = (struct zip_entry*)((char*)elm + fieldoffset); + } + return elm; +} + +void +__ZIP_ITER(unsigned short fieldoffset, __zip_iter_cb cb, + void *context, void *elm) { + if(!elm) + return; + struct zip_entry *elm_entry = ZIP_ENTRY_PTR(elm); + __ZIP_ITER(fieldoffset, cb, context, elm_entry->left); + __ZIP_ITER(fieldoffset, cb, context, elm_entry->right); + cb(elm, context); +} + +/**** amalgamated original file "/src/pubsub/ua_pubsub_config.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + */ + + +#ifdef UA_ENABLE_PUBSUB +#ifdef UA_ENABLE_PUBSUB_ETH_UADP +#endif +#endif + + +#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG + +static UA_StatusCode +createPubSubConnection(UA_Server *server, + const UA_PubSubConnectionDataType *connection, + UA_UInt32 pdsCount, UA_NodeId *pdsIdent); + +static UA_StatusCode +createWriterGroup(UA_Server *server, + const UA_WriterGroupDataType *writerGroupParameters, + UA_NodeId connectionIdent, UA_UInt32 pdsCount, + const UA_NodeId *pdsIdent); + +static UA_StatusCode +createDataSetWriter(UA_Server *server, + const UA_DataSetWriterDataType *dataSetWriterParameters, + UA_NodeId writerGroupIdent, UA_UInt32 pdsCount, + const UA_NodeId *pdsIdent); + +static UA_StatusCode +createReaderGroup(UA_Server *server, + const UA_ReaderGroupDataType *readerGroupParameters, + UA_NodeId connectionIdent); + +static UA_StatusCode +createDataSetReader(UA_Server *server, + const UA_DataSetReaderDataType *dataSetReaderParameters, + UA_NodeId readerGroupIdent); + +static UA_StatusCode +createPublishedDataSet(UA_Server *server, + const UA_PublishedDataSetDataType *publishedDataSetParameters, + UA_NodeId *publishedDataSetIdent); + +static UA_StatusCode +createDataSetFields(UA_Server *server, + const UA_NodeId *publishedDataSetIdent, + const UA_PublishedDataSetDataType *publishedDataSetParameters); + +static UA_StatusCode +generatePubSubConfigurationDataType(const UA_Server *server, + UA_PubSubConfigurationDataType *pubSubConfiguration); + +/* Gets PubSub Configuration from an ExtensionObject */ +static UA_StatusCode +extractPubSubConfigFromExtensionObject(const UA_ExtensionObject *src, + UA_PubSubConfigurationDataType **dst) { + if(src->encoding != UA_EXTENSIONOBJECT_DECODED || + src->content.decoded.type != &UA_TYPES[UA_TYPES_UABINARYFILEDATATYPE]) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] " + "Reading extensionObject failed"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + UA_UABinaryFileDataType *binFile = (UA_UABinaryFileDataType*)src->content.decoded.data; + + if(binFile->body.arrayLength != 0 || binFile->body.arrayDimensionsSize != 0) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] " + "Loading multiple configurations is not supported"); + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + + if(binFile->body.type != &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONDATATYPE]) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] " + "Invalid datatype encoded in the binary file"); + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + *dst = (UA_PubSubConfigurationDataType*)binFile->body.data; + return UA_STATUSCODE_GOOD; +} + +/* Configures a PubSub Server with given PubSubConfigurationDataType object */ +static UA_StatusCode +updatePubSubConfig(UA_Server *server, + const UA_PubSubConfigurationDataType *configurationParameters) { + if(server == NULL || configurationParameters == NULL) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_updatePubSubConfig] Invalid argument"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + UA_PubSubManager_delete(server, &server->pubSubManager); + + /* Configuration of Published DataSets: */ + UA_UInt32 pdsCount = (UA_UInt32)configurationParameters->publishedDataSetsSize; + UA_NodeId *publishedDataSetIdent = (UA_NodeId*)UA_calloc(pdsCount, sizeof(UA_NodeId)); + if(!publishedDataSetIdent) + return UA_STATUSCODE_BADOUTOFMEMORY; + + UA_StatusCode res = UA_STATUSCODE_GOOD; + for(UA_UInt32 i = 0; i < pdsCount; i++) { + res = createPublishedDataSet(server, + &configurationParameters->publishedDataSets[i], + &publishedDataSetIdent[i]); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_updatePubSubConfig] PDS creation failed"); + UA_free(publishedDataSetIdent); + return res; + } + } + + /* Configuration of PubSub Connections: */ + if(configurationParameters->connectionsSize < 1) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_updatePubSubConfig] no connection in " + "UA_PubSubConfigurationDataType"); + UA_free(publishedDataSetIdent); + return UA_STATUSCODE_GOOD; + } + + for(size_t i = 0; i < configurationParameters->connectionsSize; i++) { + res = createPubSubConnection(server, + &configurationParameters->connections[i], + pdsCount, publishedDataSetIdent); + if(res != UA_STATUSCODE_GOOD) + break; + } + + UA_free(publishedDataSetIdent); + return res; +} + +/* Function called by UA_PubSubManager_createPubSubConnection to set the + * PublisherId of a certain connection. */ +static UA_StatusCode +setConnectionPublisherId(const UA_PubSubConnectionDataType *src, + UA_PubSubConnectionConfig *dst) { + if(src->publisherId.type == &UA_TYPES[UA_TYPES_STRING]) { + dst->publisherIdType = UA_PUBSUB_PUBLISHERID_STRING; + dst->publisherId.string = *(UA_String*)src->publisherId.data; + } else if(src->publisherId.type == &UA_TYPES[UA_TYPES_BYTE] || + src->publisherId.type == &UA_TYPES[UA_TYPES_UINT16] || + src->publisherId.type == &UA_TYPES[UA_TYPES_UINT32]) { + dst->publisherIdType = UA_PUBSUB_PUBLISHERID_NUMERIC; + dst->publisherId.numeric = *(UA_UInt32*)src->publisherId.data; + } else if(src->publisherId.type == &UA_TYPES[UA_TYPES_UINT64]) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setConnectionPublisherId] PublisherId is UInt64 " + "(not implemented); Recommended dataType for PublisherId: UInt32"); + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } else { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setConnectionPublisherId] PublisherId is not valid."); + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} + +/* Function called by UA_PubSubManager_createPubSubConnection to create all WriterGroups + * and ReaderGroups that belong to a certain connection. */ +static UA_StatusCode +createComponentsForConnection(UA_Server *server, + const UA_PubSubConnectionDataType *connParams, + UA_NodeId connectionIdent, UA_UInt32 pdsCount, + const UA_NodeId *pdsIdent) { + /* WriterGroups configuration */ + UA_StatusCode res = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < connParams->writerGroupsSize; i++) { + res = createWriterGroup(server, &connParams->writerGroups[i], + connectionIdent, pdsCount, pdsIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createComponentsForConnection] " + "Error occured during %d. WriterGroup Creation", (UA_UInt32)i+1); + return res; + } + } + + /* ReaderGroups configuration */ + for(size_t j = 0; j < connParams->readerGroupsSize; j++) { + res = createReaderGroup(server, &connParams->readerGroups[j], connectionIdent); + if(res == UA_STATUSCODE_GOOD) + res |= UA_PubSubConnection_regist(server, &connectionIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createComponentsForConnection] " + "Error occured during %d. ReaderGroup Creation", (UA_UInt32)j+1); + return res; + } + } + + return res; +} + +/* Checks if transportLayer for the specified transportProfileUri exists. + * + * @param server Server object that shall be configured + * @param transportProfileUri String that specifies the transport protocol */ +static UA_Boolean +transportLayerExists(UA_Server *server, UA_String transportProfileUri) { + for(size_t i = 0; i < server->config.pubSubConfig.transportLayersSize; i++) { + if(UA_String_equal(&server->config.pubSubConfig.transportLayers[i].transportProfileUri, + &transportProfileUri)) { + return true; + } + } + return false; +} + +/* Creates transportlayer for specified transport protocol if this layer doesn't exist yet */ +static UA_StatusCode +createTransportLayer(UA_Server *server, const UA_String transportProfileUri) { + if(transportLayerExists(server, transportProfileUri)) + return UA_STATUSCODE_GOOD; + + UA_ServerConfig *config = UA_Server_getConfig(server); + UA_PubSubTransportLayer tl; + + do { + UA_String strUDP = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); + if(UA_String_equal(&transportProfileUri, &strUDP)) { + tl = UA_PubSubTransportLayerUDPMP(); + break; + } + +#ifdef UA_ENABLE_PUBSUB_ETH_UADP + UA_String strETH = + UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"); + if(UA_String_equal(&transportProfileUri, &strETH)) { + tl = UA_PubSubTransportLayerEthernet(); + break; + } +#endif + + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createTransportLayer] " + "invalid transportProfileUri"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } while(0); + + if(config->pubSubConfig.transportLayersSize > 0) { + config->pubSubConfig.transportLayers = (UA_PubSubTransportLayer *) + UA_realloc(config->pubSubConfig.transportLayers, + (config->pubSubConfig.transportLayersSize + 1) * + sizeof(UA_PubSubTransportLayer)); + } else { + config->pubSubConfig.transportLayers = (UA_PubSubTransportLayer *) + UA_calloc(1, sizeof(UA_PubSubTransportLayer)); + } + + if(config->pubSubConfig.transportLayers == NULL) { + UA_Server_delete(server); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + config->pubSubConfig.transportLayers[config->pubSubConfig.transportLayersSize] = tl; + config->pubSubConfig.transportLayersSize++; + return UA_STATUSCODE_GOOD; +} + +/* Creates PubSubConnection configuration from PubSubConnectionDataType object + * + * @param server Server object that shall be configured + * @param connParams PubSub connection configuration + * @param pdsCount Number of published DataSets + * @param pdsIdent Array of NodeIds of the published DataSets */ +static UA_StatusCode +createPubSubConnection(UA_Server *server, const UA_PubSubConnectionDataType *connParams, + UA_UInt32 pdsCount, UA_NodeId *pdsIdent) { + UA_PubSubConnectionConfig config; + memset(&config, 0, sizeof(UA_PubSubConnectionConfig)); + + config.name = connParams->name; + config.enabled = connParams->enabled; + config.transportProfileUri = connParams->transportProfileUri; + config.connectionPropertiesSize = connParams->connectionPropertiesSize; + if(config.connectionPropertiesSize > 0) { + config.connectionProperties = connParams->connectionProperties; + } + + UA_StatusCode res = setConnectionPublisherId(connParams, &config); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPubSubConnection] " + "Setting PublisherId failed"); + return res; + } + + if(connParams->address.encoding == UA_EXTENSIONOBJECT_DECODED) { + UA_Variant_setScalar(&(config.address), + connParams->address.content.decoded.data, + connParams->address.content.decoded.type); + } else { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPubSubConnection] " + "Reading connection address failed"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + if(connParams->transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED) { + UA_Variant_setScalar(&(config.connectionTransportSettings), + connParams->transportSettings.content.decoded.data, + connParams->transportSettings.content.decoded.type); + } else { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPubSubConnection] " + "TransportSettings can not be read"); + } + + res = createTransportLayer(server, connParams->transportProfileUri); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPubSubConnection] " + "Creating transportLayer failed"); + return res; + } + + /* Load connection config into server: */ + UA_NodeId connectionIdent; + res = UA_Server_addPubSubConnection(server, &config, &connectionIdent); + if(res == UA_STATUSCODE_GOOD) { + /* Configuration of all Components that belong to this connection: */ + res = createComponentsForConnection(server, connParams, connectionIdent, + pdsCount, pdsIdent); + } else { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPubSubConnection] " + "Connection creation failed"); + } + + return res; +} + +/* Function called by UA_PubSubManager_createWriterGroup to configure the messageSettings + * of a writerGroup */ +static UA_StatusCode +setWriterGroupEncodingType(const UA_WriterGroupDataType *writerGroupParameters, + UA_WriterGroupConfig *config) { + if(writerGroupParameters->messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setWriterGroupEncodingType] " + "getting message type information failed"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + if(writerGroupParameters->messageSettings.content.decoded.type == + &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]) { + config->encodingMimeType = UA_PUBSUB_ENCODING_UADP; + } else if(writerGroupParameters->messageSettings.content.decoded.type == + &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE]) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setWriterGroupEncodingType] " + "encoding type: JSON (not implemented!)"); + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } else { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setWriterGroupEncodingType] " + "invalid message encoding type"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + return UA_STATUSCODE_GOOD; +} + +/* WriterGroup configuration from WriterGroup object + * + * @param server Server object that shall be configured + * @param writerGroupParameters WriterGroup configuration + * @param connectionIdent NodeId of the PubSub connection, the WriterGroup belongs to + * @param pdsCount Number of published DataSets + * @param pdsIdent Array of NodeIds of the published DataSets */ +static UA_StatusCode +createWriterGroup(UA_Server *server, + const UA_WriterGroupDataType *writerGroupParameters, + UA_NodeId connectionIdent, UA_UInt32 pdsCount, + const UA_NodeId *pdsIdent) { + UA_WriterGroupConfig config; + memset(&config, 0, sizeof(UA_WriterGroupConfig)); + config.name = writerGroupParameters->name; + config.enabled = writerGroupParameters->enabled; + config.writerGroupId = writerGroupParameters->writerGroupId; + config.publishingInterval = writerGroupParameters->publishingInterval; + config.keepAliveTime = writerGroupParameters->keepAliveTime; + config.priority = writerGroupParameters->priority; + config.securityMode = writerGroupParameters->securityMode; + config.transportSettings = writerGroupParameters->transportSettings; + config.messageSettings = writerGroupParameters->messageSettings; + config.groupPropertiesSize = writerGroupParameters->groupPropertiesSize; + if(config.groupPropertiesSize > 0) + config.groupProperties = writerGroupParameters->groupProperties; + + config.maxEncapsulatedDataSetMessageCount = 255; /* non std parameter */ + + UA_StatusCode res = setWriterGroupEncodingType(writerGroupParameters, &config); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createWriterGroup] " + "Setting message settings failed"); + return res; + } + + /* Load config into server: */ + UA_NodeId writerGroupIdent; + res = UA_Server_addWriterGroup(server, connectionIdent, &config, &writerGroupIdent); + UA_Server_setWriterGroupOperational(server, writerGroupIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createWriterGroup] " + "Adding WriterGroup to server failed: 0x%x", res); + return res; + } + + /* Configuration of all DataSetWriters that belong to this WriterGroup */ + for(size_t dsw = 0; dsw < writerGroupParameters->dataSetWritersSize; dsw++) { + res = createDataSetWriter(server, &writerGroupParameters->dataSetWriters[dsw], + writerGroupIdent, pdsCount, pdsIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createWriterGroup] " + "DataSetWriter Creation failed."); + break; + } + } + return res; +} + +/* Function called by UA_PubSubManager_createDataSetWriter. It searches for a + * PublishedDataSet that is referenced by the DataSetWriter. If a related PDS is found, + * the DSWriter will be added to the server, otherwise, no DSWriter will be added. + * + * @param server UA_Server object that shall be configured + * @param writerGroupIdent NodeId of writerGroup, the DataSetWriter belongs to + * @param dsWriterConfig WriterGroup configuration + * @param pdsCount Number of published DataSets + * @param pdsIdent Array of NodeIds of the published DataSets */ +static UA_StatusCode +addDataSetWriterWithPdsReference(UA_Server *server, UA_NodeId writerGroupIdent, + const UA_DataSetWriterConfig *dsWriterConfig, + UA_UInt32 pdsCount, const UA_NodeId *pdsIdent) { + UA_NodeId dataSetWriterIdent; + UA_PublishedDataSetConfig pdsConfig; + UA_Boolean pdsFound = false; + + UA_StatusCode res = UA_STATUSCODE_GOOD; + for(size_t pds = 0; pds < pdsCount && res == UA_STATUSCODE_GOOD; pds++) { + res = UA_Server_getPublishedDataSetConfig(server, pdsIdent[pds], &pdsConfig); + /* members of pdsConfig must be deleted manually */ + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addDataSetWriterWithPdsReference] " + "Getting pdsConfig from NodeId failed."); + return res; + } + + if(dsWriterConfig->dataSetName.length == pdsConfig.name.length && + 0 == strncmp((const char *)dsWriterConfig->dataSetName.data, + (const char *)pdsConfig.name.data, + dsWriterConfig->dataSetName.length)) { + /* DSWriter will only be created, if a matching PDS is found: */ + res = UA_Server_addDataSetWriter(server, writerGroupIdent, pdsIdent[pds], + dsWriterConfig, &dataSetWriterIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addDataSetWriterWithPdsReference] " + "Adding DataSetWriter failed"); + } else { + pdsFound = true; + } + + UA_PublishedDataSetConfig_clear(&pdsConfig); + if(pdsFound) + break; /* break loop if corresponding publishedDataSet was found */ + } + } + + if(!pdsFound) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addDataSetWriterWithPdsReference] " + "No matching DataSet found; no DataSetWriter created"); + } + + return res; +} + +/* Creates DataSetWriter configuration from DataSetWriter object + * + * @param server UA_Server object that shall be configured + * @param dataSetWriterParameters DataSetWriter Configuration + * @param writerGroupIdent NodeId of writerGroup, the DataSetWriter belongs to + * @param pdsCount Number of published DataSets + * @param pdsIdent Array of NodeIds of the published DataSets */ +static UA_StatusCode +createDataSetWriter(UA_Server *server, + const UA_DataSetWriterDataType *dataSetWriterParameters, + UA_NodeId writerGroupIdent, UA_UInt32 pdsCount, + const UA_NodeId *pdsIdent) { + UA_DataSetWriterConfig config; + memset(&config, 0, sizeof(UA_DataSetWriterConfig)); + config.name = dataSetWriterParameters->name; + config.dataSetWriterId = dataSetWriterParameters->dataSetWriterId; + config.keyFrameCount = dataSetWriterParameters->keyFrameCount; + config.dataSetFieldContentMask = dataSetWriterParameters->dataSetFieldContentMask; + config.messageSettings = dataSetWriterParameters->messageSettings; + config.dataSetName = dataSetWriterParameters->dataSetName; + config.dataSetWriterPropertiesSize = dataSetWriterParameters->dataSetWriterPropertiesSize; + if(config.dataSetWriterPropertiesSize > 0) + config.dataSetWriterProperties = dataSetWriterParameters->dataSetWriterProperties; + + UA_StatusCode res = addDataSetWriterWithPdsReference(server, writerGroupIdent, + &config, pdsCount, pdsIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createDataSetWriter] " + "Referencing related PDS failed"); + } + + return res; +} + +/* Creates ReaderGroup configuration from ReaderGroup object + * + * @param server UA_Server object that shall be configured + * @param readerGroupParameters ReaderGroup configuration + * @param connectionIdent NodeId of the PubSub connection, the ReaderGroup belongs to */ +static UA_StatusCode +createReaderGroup(UA_Server *server, + const UA_ReaderGroupDataType *readerGroupParameters, + UA_NodeId connectionIdent) { + UA_ReaderGroupConfig config; + memset(&config, 0, sizeof(UA_ReaderGroupConfig)); + + config.name = readerGroupParameters->name; + config.securityParameters.securityMode = readerGroupParameters->securityMode; + + UA_NodeId readerGroupIdent; + UA_StatusCode res = + UA_Server_addReaderGroup(server, connectionIdent, &config, &readerGroupIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createReaderGroup] Adding ReaderGroup " + "to server failed: 0x%x", res); + return res; + } + + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createReaderGroup] ReaderGroup successfully added."); + for(UA_UInt32 i = 0; i < readerGroupParameters->dataSetReadersSize; i++) { + res = createDataSetReader(server, &readerGroupParameters->dataSetReaders[i], + readerGroupIdent); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createReaderGroup] Creating DataSetReader failed"); + break; + } + } + + if(res == UA_STATUSCODE_GOOD) + UA_Server_setReaderGroupOperational(server, readerGroupIdent); + + return res; +} + +/* Creates TargetVariables or SubscribedDataSetMirror for a given DataSetReader + * + * @param server UA_Server object that shall be configured + * @param dsReaderIdent NodeId of the DataSetReader the SubscribedDataSet belongs to + * @param dataSetReaderParameters Configuration Parameters of the DataSetReader */ +static UA_StatusCode +addSubscribedDataSet(UA_Server *server, const UA_NodeId dsReaderIdent, + const UA_ExtensionObject *subscribedDataSet) { + if(subscribedDataSet->content.decoded.type == + &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]) { + UA_TargetVariablesDataType *tmpTargetVars = (UA_TargetVariablesDataType*) + subscribedDataSet->content.decoded.data; + UA_FieldTargetVariable *targetVars = (UA_FieldTargetVariable *) + UA_calloc(tmpTargetVars->targetVariablesSize, sizeof(UA_FieldTargetVariable)); + + for(size_t index = 0; index < tmpTargetVars->targetVariablesSize; index++) { + UA_FieldTargetDataType_copy(&tmpTargetVars->targetVariables[index], + &targetVars[index].targetVariable); + } + + UA_StatusCode res = + UA_Server_DataSetReader_createTargetVariables(server, dsReaderIdent, + tmpTargetVars->targetVariablesSize, + targetVars); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addSubscribedDataSet] " + "create TargetVariables failed"); + } + + for(size_t index = 0; index < tmpTargetVars->targetVariablesSize; index++) { + UA_FieldTargetDataType_clear(&targetVars[index].targetVariable); + } + + UA_free(targetVars); + return res; + } + + if(subscribedDataSet->content.decoded.type == + &UA_TYPES[UA_TYPES_SUBSCRIBEDDATASETMIRRORDATATYPE]) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addSubscribedDataSet] " + "DataSetMirror is currently not supported"); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addSubscribedDataSet] " + "Invalid Type of SubscribedDataSet"); + return UA_STATUSCODE_BADINTERNALERROR; +} + +/* Creates DataSetReader configuration from DataSetReader object + * + * @param server UA_Server object that shall be configured + * @param dataSetReaderParameters DataSetReader configuration + * @param writerGroupIdent NodeId of readerGroupParameters, the DataSetReader belongs to */ +static UA_StatusCode +createDataSetReader(UA_Server *server, const UA_DataSetReaderDataType *dsrParams, + UA_NodeId readerGroupIdent) { + UA_DataSetReaderConfig config; + memset(&config, 0, sizeof(UA_DataSetReaderConfig)); + + config.name = dsrParams->name; + config.publisherId = dsrParams->publisherId; + config.writerGroupId = dsrParams->writerGroupId; + config.dataSetWriterId = dsrParams->dataSetWriterId; + config.dataSetMetaData = dsrParams->dataSetMetaData; + config.dataSetFieldContentMask = dsrParams->dataSetFieldContentMask; + config.messageReceiveTimeout = dsrParams->messageReceiveTimeout; + config.messageSettings = dsrParams->messageSettings; + + UA_NodeId dsReaderIdent; + UA_StatusCode res = UA_Server_addDataSetReader(server, readerGroupIdent, + &config, &dsReaderIdent); + if(res == UA_STATUSCODE_GOOD) + res = addSubscribedDataSet(server, dsReaderIdent, + &dsrParams->subscribedDataSet); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createDataSetReader] " + "create subscribedDataSet failed"); + } + + return res; +} + +/* Determines whether PublishedDataSet is of type PublishedItems or PublishedEvents. + * (PublishedEvents are currently not supported!) + * + * @param publishedDataSetParameters PublishedDataSet parameters + * @param config PublishedDataSet configuration object */ +static UA_StatusCode +setPublishedDataSetType(const UA_PublishedDataSetDataType *pdsParams, + UA_PublishedDataSetConfig *config) { + if(pdsParams->dataSetSource.encoding != UA_EXTENSIONOBJECT_DECODED) + return UA_STATUSCODE_BADINTERNALERROR; + + const UA_DataType *sourceType = pdsParams->dataSetSource.content.decoded.type; + if(sourceType == &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]) { + config->publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS; + return UA_STATUSCODE_GOOD; + } else if(sourceType == &UA_TYPES[UA_TYPES_PUBLISHEDEVENTSDATATYPE]) { + /* config.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDEVENTS; */ + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setPublishedDataSetType] Published events not supported."); + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_setPublishedDataSetType] Invalid DataSetSourceDataType."); + return UA_STATUSCODE_BADINTERNALERROR; +} + +/* Creates PublishedDataSetConfig object from PublishedDataSet object + * + * @param server UA_Server object that shall be configured + * @param pdsParams publishedDataSet configuration + * @param pdsIdent NodeId of the publishedDataSet */ +static UA_StatusCode +createPublishedDataSet(UA_Server *server, + const UA_PublishedDataSetDataType *pdsParams, + UA_NodeId *pdsIdent) { + UA_PublishedDataSetConfig config; + memset(&config, 0, sizeof(UA_PublishedDataSetConfig)); + + config.name = pdsParams->name; + UA_StatusCode res = setPublishedDataSetType(pdsParams, &config); + if(res != UA_STATUSCODE_GOOD) + return res; + + res = UA_Server_addPublishedDataSet(server, &config, pdsIdent).addResult; + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPublishedDataSet] " + "Adding PublishedDataSet failed."); + return res; + } + + /* DataSetField configuration for this publishedDataSet: */ + res = createDataSetFields(server, pdsIdent, pdsParams); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createPublishedDataSet] " + "Creating DataSetFieldConfig failed."); + } + + return res; +} + +/* Adds DataSetField Variables bound to a certain PublishedDataSet. This method does NOT + * check, whether the PublishedDataSet actually contains Variables instead of Events! + * + * @param server UA_Server object that shall be configured + * @param pdsIdent NodeId of the publishedDataSet, the DataSetField belongs to + * @param publishedDataSetParameters publishedDataSet configuration */ +static UA_StatusCode +addDataSetFieldVariables(UA_Server *server, const UA_NodeId *pdsIdent, + const UA_PublishedDataSetDataType *pdsParams) { + UA_PublishedDataItemsDataType *pdItems = (UA_PublishedDataItemsDataType *) + pdsParams->dataSetSource.content.decoded.data; + if(pdItems->publishedDataSize != pdsParams->dataSetMetaData.fieldsSize) + return UA_STATUSCODE_BADINTERNALERROR; + + for(size_t i = 0; i < pdItems->publishedDataSize; i++) { + UA_DataSetFieldConfig fc; + memset(&fc, 0, sizeof(UA_DataSetFieldConfig)); + fc.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE; + fc.field.variable.configurationVersion = pdsParams->dataSetMetaData.configurationVersion; + fc.field.variable.fieldNameAlias = pdsParams->dataSetMetaData.fields[i].name; + fc.field.variable.promotedField = pdsParams->dataSetMetaData. + fields[i].fieldFlags & 0x0001; + fc.field.variable.publishParameters = pdItems->publishedData[i]; + + UA_NodeId fieldIdent; + UA_StatusCode res = UA_Server_addDataSetField(server, *pdsIdent, &fc, &fieldIdent).result; + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_addDataSetFieldVariables] " + "Adding DataSetField Variable failed."); + return res; + } + } + + return UA_STATUSCODE_GOOD; +} + +/* Checks if PublishedDataSet contains event or variable fields and calls the + * corresponding method to add these fields to the server. + * + * @param server UA_Server object that shall be configured + * @param pdsIdent NodeId of the publishedDataSet, the DataSetFields belongs to + * @param pdsParams publishedDataSet configuration */ +static UA_StatusCode +createDataSetFields(UA_Server *server, const UA_NodeId *pdsIdent, + const UA_PublishedDataSetDataType *pdsParams) { + if(pdsParams->dataSetSource.encoding != UA_EXTENSIONOBJECT_DECODED) + return UA_STATUSCODE_BADINTERNALERROR; + + if(pdsParams->dataSetSource.content.decoded.type == + &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]) + return addDataSetFieldVariables(server, pdsIdent, pdsParams); + + /* TODO: Implement Routine for adding Event DataSetFields */ + if(pdsParams->dataSetSource.content.decoded.type == + &UA_TYPES[UA_TYPES_PUBLISHEDEVENTSDATATYPE]) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createDataSetFields] " + "Published events not supported."); + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_createDataSetFields] " + "Invalid DataSetSourceDataType."); + return UA_STATUSCODE_BADINTERNALERROR; +} + +UA_StatusCode +UA_PubSubManager_loadPubSubConfigFromByteString(UA_Server *server, + const UA_ByteString buffer) { + size_t offset = 0; + UA_ExtensionObject decodedFile; + UA_StatusCode res = UA_ExtensionObject_decodeBinary(&buffer, &offset, &decodedFile); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_decodeBinFile] decoding UA_Binary failed"); + goto cleanup; + } + + UA_PubSubConfigurationDataType *pubSubConfig = NULL; + res = extractPubSubConfigFromExtensionObject(&decodedFile, &pubSubConfig); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_loadPubSubConfigFromByteString] " + "Extracting PubSub Configuration failed"); + goto cleanup; + } + + res = updatePubSubConfig(server, pubSubConfig); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_loadPubSubConfigFromByteString] " + "Loading PubSub configuration into server failed"); + goto cleanup; + } + + cleanup: + UA_ExtensionObject_clear(&decodedFile); + return res; +} + +/* Encodes a PubSubConfigurationDataType object as ByteString using the UA Binary Data + * Encoding */ +static UA_StatusCode +encodePubSubConfiguration(UA_PubSubConfigurationDataType *configurationParameters, + UA_ByteString *buffer) { + UA_UABinaryFileDataType binFile; + memset(&binFile, 0, sizeof(UA_UABinaryFileDataType)); + /*Perhaps, additional initializations of binFile are necessary here.*/ + + UA_Variant_setScalar(&binFile.body, configurationParameters, + &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONDATATYPE]); + + UA_ExtensionObject container; + memset(&container, 0, sizeof(UA_ExtensionObject)); + container.encoding = UA_EXTENSIONOBJECT_DECODED; + container.content.decoded.type = &UA_TYPES[UA_TYPES_UABINARYFILEDATATYPE]; + container.content.decoded.data = &binFile; + + size_t fileSize = UA_ExtensionObject_calcSizeBinary(&container); + buffer->data = (UA_Byte*)UA_calloc(fileSize, sizeof(UA_Byte)); + if(buffer->data == NULL) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_encodePubSubConfiguration] Allocating buffer failed"); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + buffer->length = fileSize; + + UA_Byte *bufferPos = buffer->data; + UA_StatusCode res = + UA_ExtensionObject_encodeBinary(&container, &bufferPos, bufferPos + fileSize); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_encodePubSubConfiguration] Encoding failed"); + } + return res; +} + +static UA_StatusCode +generatePublishedDataSetDataType(const UA_PublishedDataSet *src, + UA_PublishedDataSetDataType *dst) { + if(src->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS) + return UA_STATUSCODE_BADNOTIMPLEMENTED; + + memset(dst, 0, sizeof(UA_PublishedDataSetDataType)); + + UA_PublishedDataItemsDataType *tmp = UA_PublishedDataItemsDataType_new(); + UA_String_copy(&src->config.name, &dst->name); + dst->dataSetMetaData.fieldsSize = src->fieldSize; + + size_t index = 0; + tmp->publishedDataSize = src->fieldSize; + tmp->publishedData = (UA_PublishedVariableDataType*) + UA_Array_new(tmp->publishedDataSize, &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]); + if(tmp->publishedData == NULL) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Allocation memory failed"); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + dst->dataSetMetaData.fields = (UA_FieldMetaData*) + UA_Array_new(dst->dataSetMetaData.fieldsSize, &UA_TYPES[UA_TYPES_FIELDMETADATA]); + if(dst->dataSetMetaData.fields == NULL) { + UA_free(tmp->publishedData); + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Allocation memory failed"); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + UA_DataSetField *dsf, *dsf_tmp = NULL; + TAILQ_FOREACH_SAFE(dsf ,&src->fields, listEntry, dsf_tmp) { + UA_String_copy(&dsf->config.field.variable.fieldNameAlias, + &dst->dataSetMetaData.fields[index].name); + UA_PublishedVariableDataType_copy(&dsf->config.field.variable.publishParameters, + &tmp->publishedData[index]); + UA_ConfigurationVersionDataType_copy(&dsf->config.field.variable.configurationVersion, + &dst->dataSetMetaData.configurationVersion); + dst->dataSetMetaData.fields[index].fieldFlags = + dsf->config.field.variable.promotedField; + index++; + } + UA_ExtensionObject_setValue(&dst->dataSetSource, tmp, + &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]); + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +generateDataSetWriterDataType(const UA_DataSetWriter *src, + UA_DataSetWriterDataType *dst) { + memset(dst, 0, sizeof(UA_DataSetWriterDataType)); + + UA_String_copy(&src->config.name, &dst->name); + dst->dataSetWriterId = src->config.dataSetWriterId; + dst->keyFrameCount = src->config.keyFrameCount; + dst->dataSetFieldContentMask = src->config.dataSetFieldContentMask; + UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings); + UA_String_copy(&src->config.dataSetName, &dst->dataSetName); + + dst->dataSetWriterPropertiesSize = src->config.dataSetWriterPropertiesSize; + for(size_t i = 0; i < src->config.dataSetWriterPropertiesSize; i++) { + UA_KeyValuePair_copy(&src->config.dataSetWriterProperties[i], + &dst->dataSetWriterProperties[i]); + } + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +generateWriterGroupDataType(const UA_WriterGroup *src, + UA_WriterGroupDataType *dst) { + memset(dst, 0, sizeof(UA_WriterGroupDataType)); + + UA_String_copy(&src->config.name, &dst->name); + dst->enabled = src->config.enabled; + dst->writerGroupId = src->config.writerGroupId; + dst->publishingInterval = src->config.publishingInterval; + dst->keepAliveTime = src->config.keepAliveTime; + dst->priority = src->config.priority; + dst->securityMode = src->config.securityMode; + + UA_ExtensionObject_copy(&src->config.transportSettings, &dst->transportSettings); + UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings); + + dst->groupPropertiesSize = src->config.groupPropertiesSize; + dst->groupProperties = (UA_KeyValuePair*) + UA_Array_new(dst->groupPropertiesSize, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + for(size_t index = 0; index < dst->groupPropertiesSize; index++) { + UA_KeyValuePair_copy(&src->config.groupProperties[index], + &dst->groupProperties[index]); + } + + dst->dataSetWriters = (UA_DataSetWriterDataType*) + UA_calloc(src->writersCount, sizeof(UA_DataSetWriterDataType)); + if(!dst->dataSetWriters) + return UA_STATUSCODE_BADOUTOFMEMORY; + + dst->dataSetWritersSize = src->writersCount; + + UA_DataSetWriter *dsw; + size_t dsWriterIndex = 0; + LIST_FOREACH(dsw, &src->writers, listEntry) { + UA_StatusCode res = + generateDataSetWriterDataType(dsw, &dst->dataSetWriters[dsWriterIndex]); + if(res != UA_STATUSCODE_GOOD) + return res; + dsWriterIndex++; + } + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +generateDataSetReaderDataType(const UA_DataSetReader *src, + UA_DataSetReaderDataType *dst) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + memset(dst, 0, sizeof(UA_DataSetReaderDataType)); + dst->writerGroupId = src->config.writerGroupId; + dst->dataSetWriterId = src->config.dataSetWriterId; + dst->dataSetFieldContentMask = src->config.dataSetFieldContentMask; + dst->messageReceiveTimeout = src->config.messageReceiveTimeout; + res |= UA_String_copy(&src->config.name, &dst->name); + res |= UA_Variant_copy(&src->config.publisherId, &dst->publisherId); + res |= UA_DataSetMetaDataType_copy(&src->config.dataSetMetaData, + &dst->dataSetMetaData); + res |= UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings); + + UA_TargetVariablesDataType *tmpTarget = UA_TargetVariablesDataType_new(); + if(!tmpTarget) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_ExtensionObject_setValue(&dst->subscribedDataSet, tmpTarget, + &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]); + + const UA_TargetVariables *targets = + &src->config.subscribedDataSet.subscribedDataSetTarget; + tmpTarget->targetVariables = (UA_FieldTargetDataType *) + UA_calloc(targets->targetVariablesSize, sizeof(UA_FieldTargetDataType)); + if(!tmpTarget->targetVariables) + return UA_STATUSCODE_BADOUTOFMEMORY; + tmpTarget->targetVariablesSize = targets->targetVariablesSize; + + for(size_t i = 0; i < tmpTarget->targetVariablesSize; i++) { + res |= UA_FieldTargetDataType_copy(&targets->targetVariables[i].targetVariable, + &tmpTarget->targetVariables[i]); + } + + return res; +} + +static UA_StatusCode +generateReaderGroupDataType(const UA_ReaderGroup *src, + UA_ReaderGroupDataType *dst) { + memset(dst, 0, sizeof(UA_ReaderGroupDataType)); + + UA_String_copy(&src->config.name, &dst->name); + dst->dataSetReaders = (UA_DataSetReaderDataType*) + UA_calloc(src->readersCount, sizeof(UA_DataSetReaderDataType)); + if(dst->dataSetReaders == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + dst->dataSetReadersSize = src->readersCount; + + size_t i = 0; + UA_DataSetReader *dsr, *dsr_tmp = NULL; + LIST_FOREACH_SAFE(dsr, &src->readers, listEntry, dsr_tmp) { + UA_StatusCode res = + generateDataSetReaderDataType(dsr, &dst->dataSetReaders[i]); + if(res != UA_STATUSCODE_GOOD) + return res; + i++; + } + + return UA_STATUSCODE_GOOD; +} + +/* Generates a PubSubConnectionDataType object from a PubSubConnection. */ +static UA_StatusCode +generatePubSubConnectionDataType(const UA_PubSubConnection *src, + UA_PubSubConnectionDataType *dst) { + memset(dst, 0, sizeof(UA_PubSubConnectionDataType)); + + UA_String_copy(&src->config->name, &dst->name); + UA_String_copy(&src->config->transportProfileUri, &dst->transportProfileUri); + dst->enabled = src->config->enabled; + + dst->connectionPropertiesSize = src->config->connectionPropertiesSize; + for(size_t i = 0; i < src->config->connectionPropertiesSize; i++) { + UA_KeyValuePair_copy(&src->config->connectionProperties[i], + &dst->connectionProperties[i]); + } + + if(src->config->publisherIdType == UA_PUBSUB_PUBLISHERID_NUMERIC) { + UA_Variant_setScalarCopy(&dst->publisherId, + &src->config->publisherId.numeric, + &UA_TYPES[UA_TYPES_UINT32]); + } else if(src->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) { + UA_Variant_setScalarCopy(&dst->publisherId, + &src->config->publisherId.string, + &UA_TYPES[UA_TYPES_STRING]); + } + + /* Possibly, array size and dimensions of src->config->address and + * src->config->connectionTransportSettings should be checked beforehand. */ + dst->address.encoding = UA_EXTENSIONOBJECT_DECODED; + dst->address.content.decoded.type = src->config->address.type; + UA_StatusCode res = + UA_Array_copy(src->config->address.data, 1, + &dst->address.content.decoded.data, src->config->address.type); + if(res != UA_STATUSCODE_GOOD) + return res; + + if(src->config->connectionTransportSettings.data) { + dst->transportSettings.encoding = UA_EXTENSIONOBJECT_DECODED; + dst->transportSettings.content.decoded.type = + src->config->connectionTransportSettings.type; + res = UA_Array_copy(src->config->connectionTransportSettings.data, 1, + &dst->transportSettings.content.decoded.data, + src->config->connectionTransportSettings.type); + + if(res != UA_STATUSCODE_GOOD) + return res; + } + + dst->writerGroups = (UA_WriterGroupDataType*) + UA_calloc(src->writerGroupsSize, sizeof(UA_WriterGroupDataType)); + if(dst->writerGroups == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + dst->writerGroupsSize = src->writerGroupsSize; + UA_WriterGroup *wg, *wg_tmp = NULL; + size_t wgIndex = 0; + LIST_FOREACH_SAFE(wg ,&src->writerGroups, listEntry, wg_tmp) { + res = generateWriterGroupDataType(wg, &dst->writerGroups[wgIndex]); + if(res != UA_STATUSCODE_GOOD) + return res; + wgIndex++; + } + + dst->readerGroups = (UA_ReaderGroupDataType*) + UA_calloc(src->readerGroupsSize, sizeof(UA_ReaderGroupDataType)); + if(dst->readerGroups == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + dst->readerGroupsSize = src->readerGroupsSize; + UA_ReaderGroup *rg = NULL; + size_t rgIndex = 0; + LIST_FOREACH(rg, &src->readerGroups, listEntry) { + res = generateReaderGroupDataType(rg, &dst->readerGroups[rgIndex]); + if(res != UA_STATUSCODE_GOOD) + return res; + rgIndex++; + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +generatePubSubConfigurationDataType(const UA_Server* server, + UA_PubSubConfigurationDataType *configDT) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + const UA_PubSubManager *manager = &server->pubSubManager; + memset(configDT, 0, sizeof(UA_PubSubConfigurationDataType)); + + configDT->publishedDataSets = (UA_PublishedDataSetDataType*) + UA_calloc(manager->publishedDataSetsSize, + sizeof(UA_PublishedDataSetDataType)); + if(configDT->publishedDataSets == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + configDT->publishedDataSetsSize = manager->publishedDataSetsSize; + + UA_PublishedDataSet *pds; + UA_UInt32 pdsIndex = 0; + TAILQ_FOREACH(pds, &manager->publishedDataSets, listEntry) { + UA_PublishedDataSetDataType *dst = &configDT->publishedDataSets[pdsIndex]; + res = generatePublishedDataSetDataType(pds, dst); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_generatePubSubConfigurationDataType] " + "retrieving PublishedDataSet configuration failed"); + return res; + } + pdsIndex++; + } + + configDT->connections = (UA_PubSubConnectionDataType*) + UA_calloc(manager->connectionsSize, sizeof(UA_PubSubConnectionDataType)); + if(configDT->connections == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + configDT->connectionsSize = manager->connectionsSize; + + UA_UInt32 connectionIndex = 0; + UA_PubSubConnection *connection; + TAILQ_FOREACH(connection, &manager->connections, listEntry) { + UA_PubSubConnectionDataType *cdt = &configDT->connections[connectionIndex]; + res = generatePubSubConnectionDataType(connection, cdt); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "[UA_PubSubManager_generatePubSubConfigurationDataType] " + "retrieving PubSubConnection configuration failed"); + return res; + } + connectionIndex++; + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_PubSubManager_getEncodedPubSubConfiguration(UA_Server *server, + UA_ByteString *buffer) { + UA_PubSubConfigurationDataType config; + memset(&config, 0, sizeof(UA_PubSubConfigurationDataType)); + + UA_StatusCode res = generatePubSubConfigurationDataType(server, &config); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "retrieving PubSub configuration from server failed"); + goto cleanup; + } + + res = encodePubSubConfiguration(&config, buffer); + if(res != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "encoding PubSub configuration failed"); + goto cleanup; + } + + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Saving PubSub config was successful"); + + cleanup: + UA_PubSubConfigurationDataType_clear(&config); + return res; +} + +#endif /* UA_ENABLE_PUBSUB_FILE_CONFIG */ + +/**** amalgamated original file "/build/src_generated/open62541/namespace0_generated.c" ****/ /* WARNING: This is a generated file. * Any manual changes will be overwritten. */ @@ -46272,9 +51978,9 @@ UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.inverseName = UA_LOCALIZEDTEXT("", "AddInOf"); attr.displayName = UA_LOCALIZEDTEXT("", "HasAddIn"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 17604), -UA_NODEID_NUMERIC(ns[0], 32), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 17604LU), +UA_NODEID_NUMERIC(ns[0], 32LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "HasAddIn"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); @@ -46283,793 +51989,770 @@ return retVal; static UA_StatusCode function_namespace0_generated_0_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 17604) -); -} - -/* HasInterface - ns=0;i=17603 */ - -static UA_StatusCode function_namespace0_generated_1_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; -attr.inverseName = UA_LOCALIZEDTEXT("", "InterfaceOf"); -attr.displayName = UA_LOCALIZEDTEXT("", "HasInterface"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 17603), -UA_NODEID_NUMERIC(ns[0], 32), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "HasInterface"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_1_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 17603) +UA_NODEID_NUMERIC(ns[0], 17604LU) ); } /* HasHistoricalConfiguration - ns=0;i=56 */ -static UA_StatusCode function_namespace0_generated_2_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_1_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.inverseName = UA_LOCALIZEDTEXT("", "HistoricalConfigurationOf"); attr.displayName = UA_LOCALIZEDTEXT("", "HasHistoricalConfiguration"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 56), -UA_NODEID_NUMERIC(ns[0], 44), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 56LU), +UA_NODEID_NUMERIC(ns[0], 44LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "HasHistoricalConfiguration"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_2_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_1_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 56) +UA_NODEID_NUMERIC(ns[0], 56LU) ); } /* HasEffect - ns=0;i=54 */ -static UA_StatusCode function_namespace0_generated_3_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_2_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.inverseName = UA_LOCALIZEDTEXT("", "MayBeEffectedBy"); attr.displayName = UA_LOCALIZEDTEXT("", "HasEffect"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 54), -UA_NODEID_NUMERIC(ns[0], 32), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 54LU), +UA_NODEID_NUMERIC(ns[0], 32LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "HasEffect"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_3_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_2_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 54) +UA_NODEID_NUMERIC(ns[0], 54LU) ); } /* HasCause - ns=0;i=53 */ -static UA_StatusCode function_namespace0_generated_4_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_3_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.inverseName = UA_LOCALIZEDTEXT("", "MayBeCausedBy"); attr.displayName = UA_LOCALIZEDTEXT("", "HasCause"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 53), -UA_NODEID_NUMERIC(ns[0], 32), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 53LU), +UA_NODEID_NUMERIC(ns[0], 32LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "HasCause"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_4_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_3_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 53) +UA_NODEID_NUMERIC(ns[0], 53LU) ); } /* ToState - ns=0;i=52 */ -static UA_StatusCode function_namespace0_generated_5_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_4_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.inverseName = UA_LOCALIZEDTEXT("", "FromTransition"); attr.displayName = UA_LOCALIZEDTEXT("", "ToState"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 52), -UA_NODEID_NUMERIC(ns[0], 32), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 52LU), +UA_NODEID_NUMERIC(ns[0], 32LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "ToState"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_5_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_4_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 52) +UA_NODEID_NUMERIC(ns[0], 52LU) ); } /* FromState - ns=0;i=51 */ -static UA_StatusCode function_namespace0_generated_6_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_5_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.inverseName = UA_LOCALIZEDTEXT("", "ToTransition"); attr.displayName = UA_LOCALIZEDTEXT("", "FromState"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, -UA_NODEID_NUMERIC(ns[0], 51), -UA_NODEID_NUMERIC(ns[0], 32), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 51LU), +UA_NODEID_NUMERIC(ns[0], 32LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "FromState"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_6_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_5_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 51) +UA_NODEID_NUMERIC(ns[0], 51LU) ); } /* DiagnosticInfo - ns=0;i=25 */ -static UA_StatusCode function_namespace0_generated_7_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_6_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "DiagnosticInfo"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 25), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 25LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DiagnosticInfo"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_7_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_6_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 25) +UA_NODEID_NUMERIC(ns[0], 25LU) ); } /* DataValue - ns=0;i=23 */ -static UA_StatusCode function_namespace0_generated_8_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_7_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "DataValue"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 23), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 23LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DataValue"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_8_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_7_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 23) +UA_NODEID_NUMERIC(ns[0], 23LU) ); } /* Structure - ns=0;i=22 */ -static UA_StatusCode function_namespace0_generated_9_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_8_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.isAbstract = true; attr.displayName = UA_LOCALIZEDTEXT("", "Structure"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Structure"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_9_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_8_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 22) +UA_NODEID_NUMERIC(ns[0], 22LU) ); } -/* ServerStatusDataType - ns=0;i=862 */ +/* TimeZoneDataType - ns=0;i=8912 */ -static UA_StatusCode function_namespace0_generated_10_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_9_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusDataType"); +attr.displayName = UA_LOCALIZEDTEXT("", "TimeZoneDataType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 862), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerStatusDataType"), +UA_NODEID_NUMERIC(ns[0], 8912LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "TimeZoneDataType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_10_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_9_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 862) +UA_NODEID_NUMERIC(ns[0], 8912LU) ); } -/* EnumValueType - ns=0;i=7594 */ +/* EUInformation - ns=0;i=887 */ -static UA_StatusCode function_namespace0_generated_11_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_10_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType"); +attr.displayName = UA_LOCALIZEDTEXT("", "EUInformation"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 7594), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "EnumValueType"), +UA_NODEID_NUMERIC(ns[0], 887LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "EUInformation"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_11_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_10_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 7594) +UA_NODEID_NUMERIC(ns[0], 887LU) ); } -/* Union - ns=0;i=12756 */ +/* Range - ns=0;i=884 */ -static UA_StatusCode function_namespace0_generated_12_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_11_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.isAbstract = true; -attr.displayName = UA_LOCALIZEDTEXT("", "Union"); +attr.displayName = UA_LOCALIZEDTEXT("", "Range"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 12756), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Union"), +UA_NODEID_NUMERIC(ns[0], 884LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Range"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_12_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_11_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 12756) +UA_NODEID_NUMERIC(ns[0], 884LU) ); } -/* EUInformation - ns=0;i=887 */ +/* ServerStatusDataType - ns=0;i=862 */ -static UA_StatusCode function_namespace0_generated_13_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_12_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "EUInformation"); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusDataType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 887), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "EUInformation"), +UA_NODEID_NUMERIC(ns[0], 862LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerStatusDataType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_13_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_12_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 887) +UA_NODEID_NUMERIC(ns[0], 862LU) ); } -/* TimeZoneDataType - ns=0;i=8912 */ +/* EnumValueType - ns=0;i=7594 */ -static UA_StatusCode function_namespace0_generated_14_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_13_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "TimeZoneDataType"); +attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 8912), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "TimeZoneDataType"), +UA_NODEID_NUMERIC(ns[0], 7594LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "EnumValueType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_14_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_13_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 8912) +UA_NODEID_NUMERIC(ns[0], 7594LU) ); } /* SignedSoftwareCertificate - ns=0;i=344 */ -static UA_StatusCode function_namespace0_generated_15_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_14_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "SignedSoftwareCertificate"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 344), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 344LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "SignedSoftwareCertificate"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_15_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_14_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 344) +UA_NODEID_NUMERIC(ns[0], 344LU) ); } -/* ServerDiagnosticsSummaryDataType - ns=0;i=859 */ +/* BuildInfo - ns=0;i=338 */ -static UA_StatusCode function_namespace0_generated_16_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_15_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryDataType"); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 859), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummaryDataType"), +UA_NODEID_NUMERIC(ns[0], 338LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "BuildInfo"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_16_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_15_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 859) +UA_NODEID_NUMERIC(ns[0], 338LU) ); } /* Argument - ns=0;i=296 */ -static UA_StatusCode function_namespace0_generated_17_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_16_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Argument"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 296), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 296LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Argument"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_17_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 296) -); -} - -/* Range - ns=0;i=884 */ - -static UA_StatusCode function_namespace0_generated_18_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Range"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 884), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Range"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_18_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_16_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 884) +UA_NODEID_NUMERIC(ns[0], 296LU) ); } -/* BuildInfo - ns=0;i=338 */ +/* Union - ns=0;i=12756 */ -static UA_StatusCode function_namespace0_generated_19_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_17_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo"); +attr.isAbstract = true; +attr.displayName = UA_LOCALIZEDTEXT("", "Union"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 338), -UA_NODEID_NUMERIC(ns[0], 22), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "BuildInfo"), +UA_NODEID_NUMERIC(ns[0], 12756LU), +UA_NODEID_NUMERIC(ns[0], 22LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Union"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_19_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_17_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 338) +UA_NODEID_NUMERIC(ns[0], 12756LU) ); } /* LocalizedText - ns=0;i=21 */ -static UA_StatusCode function_namespace0_generated_20_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_18_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "LocalizedText"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 21), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 21LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "LocalizedText"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_20_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_18_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 21) +UA_NODEID_NUMERIC(ns[0], 21LU) ); } /* QualifiedName - ns=0;i=20 */ -static UA_StatusCode function_namespace0_generated_21_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_19_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "QualifiedName"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 20), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 20LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "QualifiedName"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_21_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_19_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 20) +UA_NODEID_NUMERIC(ns[0], 20LU) ); } /* StatusCode - ns=0;i=19 */ -static UA_StatusCode function_namespace0_generated_22_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_20_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "StatusCode"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 19), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 19LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "StatusCode"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_22_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_20_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 19) +UA_NODEID_NUMERIC(ns[0], 19LU) ); } /* ExpandedNodeId - ns=0;i=18 */ -static UA_StatusCode function_namespace0_generated_23_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_21_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "ExpandedNodeId"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 18), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 18LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "ExpandedNodeId"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_23_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_21_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 18) +UA_NODEID_NUMERIC(ns[0], 18LU) ); } /* NodeId - ns=0;i=17 */ -static UA_StatusCode function_namespace0_generated_24_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_22_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "NodeId"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 17), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 17LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "NodeId"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_24_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_22_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 17) +UA_NODEID_NUMERIC(ns[0], 17LU) ); } /* XmlElement - ns=0;i=16 */ -static UA_StatusCode function_namespace0_generated_25_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_23_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "XmlElement"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 16), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 16LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "XmlElement"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_25_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_23_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 16) +UA_NODEID_NUMERIC(ns[0], 16LU) ); } /* ByteString - ns=0;i=15 */ -static UA_StatusCode function_namespace0_generated_26_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_24_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "ByteString"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 15), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 15LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "ByteString"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_26_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_24_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 15) +UA_NODEID_NUMERIC(ns[0], 15LU) ); } /* Image - ns=0;i=30 */ -static UA_StatusCode function_namespace0_generated_27_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_25_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.isAbstract = true; attr.displayName = UA_LOCALIZEDTEXT("", "Image"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 30), -UA_NODEID_NUMERIC(ns[0], 15), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 30LU), +UA_NODEID_NUMERIC(ns[0], 15LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Image"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_27_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_25_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 30) +UA_NODEID_NUMERIC(ns[0], 30LU) ); } /* Guid - ns=0;i=14 */ -static UA_StatusCode function_namespace0_generated_28_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_26_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Guid"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 14), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 14LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Guid"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_28_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_26_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 14) +UA_NODEID_NUMERIC(ns[0], 14LU) ); } /* DateTime - ns=0;i=13 */ -static UA_StatusCode function_namespace0_generated_29_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_27_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "DateTime"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 13), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 13LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DateTime"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_29_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_27_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 13) +UA_NODEID_NUMERIC(ns[0], 13LU) ); } /* UtcTime - ns=0;i=294 */ -static UA_StatusCode function_namespace0_generated_30_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_28_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "UtcTime"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 294), -UA_NODEID_NUMERIC(ns[0], 13), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 294LU), +UA_NODEID_NUMERIC(ns[0], 13LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "UtcTime"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_30_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_28_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 294) +UA_NODEID_NUMERIC(ns[0], 294LU) ); } /* String - ns=0;i=12 */ -static UA_StatusCode function_namespace0_generated_31_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_29_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "String"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 12), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 12LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "String"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_31_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_29_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 12) +UA_NODEID_NUMERIC(ns[0], 12LU) ); } /* LocaleId - ns=0;i=295 */ -static UA_StatusCode function_namespace0_generated_32_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_30_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "LocaleId"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 295), -UA_NODEID_NUMERIC(ns[0], 12), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 295LU), +UA_NODEID_NUMERIC(ns[0], 12LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "LocaleId"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_32_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_30_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 295) +UA_NODEID_NUMERIC(ns[0], 295LU) ); } /* Boolean - ns=0;i=1 */ -static UA_StatusCode function_namespace0_generated_33_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_31_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Boolean"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 1), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 1LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Boolean"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_33_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_31_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 1) +UA_NODEID_NUMERIC(ns[0], 1LU) ); } /* Enumeration - ns=0;i=29 */ -static UA_StatusCode function_namespace0_generated_34_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_32_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.isAbstract = true; attr.displayName = UA_LOCALIZEDTEXT("", "Enumeration"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 29), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 29LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Enumeration"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_34_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_32_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 29) +UA_NODEID_NUMERIC(ns[0], 29LU) ); } -/* NamingRuleType - ns=0;i=120 */ +/* ServerState - ns=0;i=852 */ -static UA_StatusCode function_namespace0_generated_35_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_33_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "NamingRuleType"); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerState"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 120), -UA_NODEID_NUMERIC(ns[0], 29), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "NamingRuleType"), +UA_NODEID_NUMERIC(ns[0], 852LU), +UA_NODEID_NUMERIC(ns[0], 29LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerState"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_35_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_33_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 120) +UA_NODEID_NUMERIC(ns[0], 852LU) ); } -/* EnumValues - ns=0;i=12169 */ +/* RedundancySupport - ns=0;i=851 */ -static UA_StatusCode function_namespace0_generated_36_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_34_begin(UA_Server *server, UA_UInt16* ns) { +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 851LU), +UA_NODEID_NUMERIC(ns[0], 29LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +return retVal; +} + +static UA_StatusCode function_namespace0_generated_34_finish(UA_Server *server, UA_UInt16* ns) { +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 851LU) +); +} + +/* EnumStrings - ns=0;i=7611 */ + +static UA_StatusCode function_namespace0_generated_35_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; @@ -47080,69 +52763,57 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594); -UA_EnumValueType variablenode_ns_0_i_12169_variant_DataContents[3]; - -UA_init(&variablenode_ns_0_i_12169_variant_DataContents[0], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); -variablenode_ns_0_i_12169_variant_DataContents[0].value = (UA_Int64) 1; -variablenode_ns_0_i_12169_variant_DataContents[0].displayName = UA_LOCALIZEDTEXT("", "Mandatory"); -variablenode_ns_0_i_12169_variant_DataContents[0].description = UA_LOCALIZEDTEXT("", "The BrowseName must appear in all instances of the type."); - -UA_init(&variablenode_ns_0_i_12169_variant_DataContents[1], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); -variablenode_ns_0_i_12169_variant_DataContents[1].value = (UA_Int64) 2; -variablenode_ns_0_i_12169_variant_DataContents[1].displayName = UA_LOCALIZEDTEXT("", "Optional"); -variablenode_ns_0_i_12169_variant_DataContents[1].description = UA_LOCALIZEDTEXT("", "The BrowseName may appear in an instance of the type."); - -UA_init(&variablenode_ns_0_i_12169_variant_DataContents[2], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); -variablenode_ns_0_i_12169_variant_DataContents[2].value = (UA_Int64) 3; -variablenode_ns_0_i_12169_variant_DataContents[2].displayName = UA_LOCALIZEDTEXT("", "Constraint"); -variablenode_ns_0_i_12169_variant_DataContents[2].description = UA_LOCALIZEDTEXT("", "The modelling rule defines a constraint and the BrowseName is not used in an instance of the type."); -UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12169_variant_DataContents, (UA_Int32) 3, &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); -attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues"); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); +UA_LocalizedText variablenode_ns_0_i_7611_variant_DataContents[6]; +variablenode_ns_0_i_7611_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "None"); +variablenode_ns_0_i_7611_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "Cold"); +variablenode_ns_0_i_7611_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "Warm"); +variablenode_ns_0_i_7611_variant_DataContents[3] = UA_LOCALIZEDTEXT("", "Hot"); +variablenode_ns_0_i_7611_variant_DataContents[4] = UA_LOCALIZEDTEXT("", "Transparent"); +variablenode_ns_0_i_7611_variant_DataContents[5] = UA_LOCALIZEDTEXT("", "HotAndMirrored"); +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_7611_variant_DataContents, (UA_Int32) 6, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); +attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 12169), -UA_NODEID_NUMERIC(ns[0], 120), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "EnumValues"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 7611LU), +UA_NODEID_NUMERIC(ns[0], 851LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "EnumStrings"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); - - - return retVal; } -static UA_StatusCode function_namespace0_generated_36_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_35_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 12169) +UA_NODEID_NUMERIC(ns[0], 7611LU) ); } /* AxisScaleEnumeration - ns=0;i=12077 */ -static UA_StatusCode function_namespace0_generated_37_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_36_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "AxisScaleEnumeration"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 12077), -UA_NODEID_NUMERIC(ns[0], 29), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 12077LU), +UA_NODEID_NUMERIC(ns[0], 29LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "AxisScaleEnumeration"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_37_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_36_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 12077) +UA_NODEID_NUMERIC(ns[0], 12077LU) ); } /* EnumStrings - ns=0;i=12078 */ -static UA_StatusCode function_namespace0_generated_38_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_37_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; @@ -47153,7 +52824,7 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); UA_LocalizedText variablenode_ns_0_i_12078_variant_DataContents[3]; variablenode_ns_0_i_12078_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "Linear"); variablenode_ns_0_i_12078_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "Log"); @@ -47161,68 +52832,46 @@ variablenode_ns_0_i_12078_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "Ln"); UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12078_variant_DataContents, (UA_Int32) 3, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 12078), -UA_NODEID_NUMERIC(ns[0], 12077), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 12078LU), +UA_NODEID_NUMERIC(ns[0], 12077LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "EnumStrings"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_38_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 12078) -); -} - -/* ServerState - ns=0;i=852 */ - -static UA_StatusCode function_namespace0_generated_39_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerState"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 852), -UA_NODEID_NUMERIC(ns[0], 29), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerState"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_39_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_37_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 852) +UA_NODEID_NUMERIC(ns[0], 12078LU) ); } -/* RedundancySupport - ns=0;i=851 */ +/* NamingRuleType - ns=0;i=120 */ -static UA_StatusCode function_namespace0_generated_40_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_38_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); +attr.displayName = UA_LOCALIZEDTEXT("", "NamingRuleType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 851), -UA_NODEID_NUMERIC(ns[0], 29), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), +UA_NODEID_NUMERIC(ns[0], 120LU), +UA_NODEID_NUMERIC(ns[0], 29LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "NamingRuleType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_40_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_38_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 851) +UA_NODEID_NUMERIC(ns[0], 120LU) ); } -/* EnumStrings - ns=0;i=7611 */ +/* EnumValues - ns=0;i=12169 */ -static UA_StatusCode function_namespace0_generated_41_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_39_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; @@ -47233,613 +52882,621 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); -UA_LocalizedText variablenode_ns_0_i_7611_variant_DataContents[6]; -variablenode_ns_0_i_7611_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "None"); -variablenode_ns_0_i_7611_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "Cold"); -variablenode_ns_0_i_7611_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "Warm"); -variablenode_ns_0_i_7611_variant_DataContents[3] = UA_LOCALIZEDTEXT("", "Hot"); -variablenode_ns_0_i_7611_variant_DataContents[4] = UA_LOCALIZEDTEXT("", "Transparent"); -variablenode_ns_0_i_7611_variant_DataContents[5] = UA_LOCALIZEDTEXT("", "HotAndMirrored"); -UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_7611_variant_DataContents, (UA_Int32) 6, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); -attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings"); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594LU); +UA_EnumValueType variablenode_ns_0_i_12169_variant_DataContents[3]; + +UA_init(&variablenode_ns_0_i_12169_variant_DataContents[0], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); +variablenode_ns_0_i_12169_variant_DataContents[0].value = (UA_Int64) 1; +variablenode_ns_0_i_12169_variant_DataContents[0].displayName = UA_LOCALIZEDTEXT("", "Mandatory"); +variablenode_ns_0_i_12169_variant_DataContents[0].description = UA_LOCALIZEDTEXT("", "The BrowseName must appear in all instances of the type."); + +UA_init(&variablenode_ns_0_i_12169_variant_DataContents[1], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); +variablenode_ns_0_i_12169_variant_DataContents[1].value = (UA_Int64) 2; +variablenode_ns_0_i_12169_variant_DataContents[1].displayName = UA_LOCALIZEDTEXT("", "Optional"); +variablenode_ns_0_i_12169_variant_DataContents[1].description = UA_LOCALIZEDTEXT("", "The BrowseName may appear in an instance of the type."); + +UA_init(&variablenode_ns_0_i_12169_variant_DataContents[2], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); +variablenode_ns_0_i_12169_variant_DataContents[2].value = (UA_Int64) 3; +variablenode_ns_0_i_12169_variant_DataContents[2].displayName = UA_LOCALIZEDTEXT("", "Constraint"); +variablenode_ns_0_i_12169_variant_DataContents[2].description = UA_LOCALIZEDTEXT("", "The modelling rule defines a constraint and the BrowseName is not used in an instance of the type."); +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12169_variant_DataContents, (UA_Int32) 3, &UA_TYPES[UA_TYPES_ENUMVALUETYPE]); +attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 7611), -UA_NODEID_NUMERIC(ns[0], 851), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "EnumStrings"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 12169LU), +UA_NODEID_NUMERIC(ns[0], 120LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "EnumValues"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); + + + return retVal; } -static UA_StatusCode function_namespace0_generated_41_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_39_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 7611) +UA_NODEID_NUMERIC(ns[0], 12169LU) ); } /* Number - ns=0;i=26 */ -static UA_StatusCode function_namespace0_generated_42_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_40_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.isAbstract = true; attr.displayName = UA_LOCALIZEDTEXT("", "Number"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 26), -UA_NODEID_NUMERIC(ns[0], 24), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 26LU), +UA_NODEID_NUMERIC(ns[0], 24LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "Number"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_42_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_40_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 26) +UA_NODEID_NUMERIC(ns[0], 26LU) ); } -/* UInteger - ns=0;i=28 */ +/* Decimal - ns=0;i=50 */ -static UA_StatusCode function_namespace0_generated_43_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_41_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.isAbstract = true; -attr.displayName = UA_LOCALIZEDTEXT("", "UInteger"); +attr.displayName = UA_LOCALIZEDTEXT("", "Decimal"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 28), -UA_NODEID_NUMERIC(ns[0], 26), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "UInteger"), +UA_NODEID_NUMERIC(ns[0], 50LU), +UA_NODEID_NUMERIC(ns[0], 26LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Decimal"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_43_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_41_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 28) +UA_NODEID_NUMERIC(ns[0], 50LU) ); } -/* UInt64 - ns=0;i=9 */ +/* UInteger - ns=0;i=28 */ -static UA_StatusCode function_namespace0_generated_44_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_42_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "UInt64"); +attr.isAbstract = true; +attr.displayName = UA_LOCALIZEDTEXT("", "UInteger"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 9), -UA_NODEID_NUMERIC(ns[0], 28), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "UInt64"), +UA_NODEID_NUMERIC(ns[0], 28LU), +UA_NODEID_NUMERIC(ns[0], 26LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "UInteger"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_44_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_42_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 9) +UA_NODEID_NUMERIC(ns[0], 28LU) ); } -/* Byte - ns=0;i=3 */ +/* UInt64 - ns=0;i=9 */ -static UA_StatusCode function_namespace0_generated_45_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_43_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Byte"); +attr.displayName = UA_LOCALIZEDTEXT("", "UInt64"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 3), -UA_NODEID_NUMERIC(ns[0], 28), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Byte"), +UA_NODEID_NUMERIC(ns[0], 9LU), +UA_NODEID_NUMERIC(ns[0], 28LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "UInt64"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_45_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_43_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3) +UA_NODEID_NUMERIC(ns[0], 9LU) ); } /* UInt32 - ns=0;i=7 */ -static UA_StatusCode function_namespace0_generated_46_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_44_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "UInt32"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 7), -UA_NODEID_NUMERIC(ns[0], 28), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 7LU), +UA_NODEID_NUMERIC(ns[0], 28LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "UInt32"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_46_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_44_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 7) +UA_NODEID_NUMERIC(ns[0], 7LU) ); } /* UInt16 - ns=0;i=5 */ -static UA_StatusCode function_namespace0_generated_47_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_45_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "UInt16"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 5), -UA_NODEID_NUMERIC(ns[0], 28), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 5LU), +UA_NODEID_NUMERIC(ns[0], 28LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "UInt16"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_47_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_45_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 5) +UA_NODEID_NUMERIC(ns[0], 5LU) ); } -/* Integer - ns=0;i=27 */ +/* Byte - ns=0;i=3 */ -static UA_StatusCode function_namespace0_generated_48_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_46_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.isAbstract = true; -attr.displayName = UA_LOCALIZEDTEXT("", "Integer"); +attr.displayName = UA_LOCALIZEDTEXT("", "Byte"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 27), -UA_NODEID_NUMERIC(ns[0], 26), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Integer"), +UA_NODEID_NUMERIC(ns[0], 3LU), +UA_NODEID_NUMERIC(ns[0], 28LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Byte"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_48_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_46_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 27) +UA_NODEID_NUMERIC(ns[0], 3LU) ); } -/* Int16 - ns=0;i=4 */ +/* Integer - ns=0;i=27 */ -static UA_StatusCode function_namespace0_generated_49_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_47_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Int16"); +attr.isAbstract = true; +attr.displayName = UA_LOCALIZEDTEXT("", "Integer"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 4), -UA_NODEID_NUMERIC(ns[0], 27), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Int16"), +UA_NODEID_NUMERIC(ns[0], 27LU), +UA_NODEID_NUMERIC(ns[0], 26LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Integer"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_49_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_47_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 4) +UA_NODEID_NUMERIC(ns[0], 27LU) ); } -/* Int32 - ns=0;i=6 */ +/* Int64 - ns=0;i=8 */ -static UA_StatusCode function_namespace0_generated_50_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_48_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Int32"); +attr.displayName = UA_LOCALIZEDTEXT("", "Int64"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 6), -UA_NODEID_NUMERIC(ns[0], 27), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Int32"), +UA_NODEID_NUMERIC(ns[0], 8LU), +UA_NODEID_NUMERIC(ns[0], 27LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Int64"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_50_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_48_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 6) +UA_NODEID_NUMERIC(ns[0], 8LU) ); } -/* Int64 - ns=0;i=8 */ +/* Int32 - ns=0;i=6 */ -static UA_StatusCode function_namespace0_generated_51_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_49_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Int64"); +attr.displayName = UA_LOCALIZEDTEXT("", "Int32"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 8), -UA_NODEID_NUMERIC(ns[0], 27), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Int64"), +UA_NODEID_NUMERIC(ns[0], 6LU), +UA_NODEID_NUMERIC(ns[0], 27LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Int32"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_51_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_49_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 8) +UA_NODEID_NUMERIC(ns[0], 6LU) ); } -/* SByte - ns=0;i=2 */ +/* Int16 - ns=0;i=4 */ -static UA_StatusCode function_namespace0_generated_52_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_50_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "SByte"); +attr.displayName = UA_LOCALIZEDTEXT("", "Int16"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 2), -UA_NODEID_NUMERIC(ns[0], 27), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "SByte"), +UA_NODEID_NUMERIC(ns[0], 4LU), +UA_NODEID_NUMERIC(ns[0], 27LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Int16"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_52_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_50_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2) +UA_NODEID_NUMERIC(ns[0], 4LU) ); } -/* Float - ns=0;i=10 */ +/* SByte - ns=0;i=2 */ -static UA_StatusCode function_namespace0_generated_53_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_51_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Float"); +attr.displayName = UA_LOCALIZEDTEXT("", "SByte"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 10), -UA_NODEID_NUMERIC(ns[0], 26), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Float"), +UA_NODEID_NUMERIC(ns[0], 2LU), +UA_NODEID_NUMERIC(ns[0], 27LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "SByte"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_53_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_51_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 10) +UA_NODEID_NUMERIC(ns[0], 2LU) ); } -/* Decimal - ns=0;i=50 */ +/* Double - ns=0;i=11 */ -static UA_StatusCode function_namespace0_generated_54_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_52_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Decimal"); +attr.displayName = UA_LOCALIZEDTEXT("", "Double"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 50), -UA_NODEID_NUMERIC(ns[0], 26), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Decimal"), +UA_NODEID_NUMERIC(ns[0], 11LU), +UA_NODEID_NUMERIC(ns[0], 26LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Double"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_54_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_52_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 50) +UA_NODEID_NUMERIC(ns[0], 11LU) ); } -/* Double - ns=0;i=11 */ +/* Duration - ns=0;i=290 */ -static UA_StatusCode function_namespace0_generated_55_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_53_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Double"); +attr.displayName = UA_LOCALIZEDTEXT("", "Duration"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 11), -UA_NODEID_NUMERIC(ns[0], 26), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Double"), +UA_NODEID_NUMERIC(ns[0], 290LU), +UA_NODEID_NUMERIC(ns[0], 11LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Duration"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_55_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_53_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11) +UA_NODEID_NUMERIC(ns[0], 290LU) ); } -/* Duration - ns=0;i=290 */ +/* Float - ns=0;i=10 */ -static UA_StatusCode function_namespace0_generated_56_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_54_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Duration"); +attr.displayName = UA_LOCALIZEDTEXT("", "Float"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, -UA_NODEID_NUMERIC(ns[0], 290), -UA_NODEID_NUMERIC(ns[0], 11), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "Duration"), +UA_NODEID_NUMERIC(ns[0], 10LU), +UA_NODEID_NUMERIC(ns[0], 26LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "Float"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_56_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_54_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 290) +UA_NODEID_NUMERIC(ns[0], 10LU) ); } /* DataItemType - ns=0;i=2365 */ -static UA_StatusCode function_namespace0_generated_57_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_55_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; attr.valueRank = -2; /* DataType inherited */ -attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24LU); attr.displayName = UA_LOCALIZEDTEXT("", "DataItemType"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "A variable that contains live automation data."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2365), -UA_NODEID_NUMERIC(ns[0], 63), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 2365LU), +UA_NODEID_NUMERIC(ns[0], 63LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DataItemType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_57_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_55_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2365) +UA_NODEID_NUMERIC(ns[0], 2365LU) ); } -/* AnalogItemType - ns=0;i=2368 */ +/* DiscreteItemType - ns=0;i=2372 */ -static UA_StatusCode function_namespace0_generated_58_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_56_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.isAbstract = true; attr.valueRank = -2; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 26); -attr.displayName = UA_LOCALIZEDTEXT("", "AnalogItemType"); +/* DataType inherited */ +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24LU); +attr.displayName = UA_LOCALIZEDTEXT("", "DiscreteItemType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2368), -UA_NODEID_NUMERIC(ns[0], 2365), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "AnalogItemType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 2372LU), +UA_NODEID_NUMERIC(ns[0], 2365LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "DiscreteItemType"), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_58_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_56_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2368) +UA_NODEID_NUMERIC(ns[0], 2372LU) ); } -/* InstrumentRange - ns=0;i=2370 */ +/* MultiStateDiscreteType - ns=0;i=2376 */ -static UA_StatusCode function_namespace0_generated_59_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_57_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 884); -attr.displayName = UA_LOCALIZEDTEXT("", "InstrumentRange"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2370), -UA_NODEID_NUMERIC(ns[0], 2368), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "InstrumentRange"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 28LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateDiscreteType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 2376LU), +UA_NODEID_NUMERIC(ns[0], 2372LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "MultiStateDiscreteType"), +UA_NODEID_NUMERIC(ns[0], 0LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_59_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_57_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2370) +UA_NODEID_NUMERIC(ns[0], 2376LU) ); } -/* EngineeringUnits - ns=0;i=2371 */ +/* EnumStrings - ns=0;i=2377 */ -static UA_StatusCode function_namespace0_generated_60_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_58_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 887); -attr.displayName = UA_LOCALIZEDTEXT("", "EngineeringUnits"); +attr.valueRank = 1; +attr.arrayDimensionsSize = 1; +UA_UInt32 arrayDimensions[1]; +arrayDimensions[0] = 0; +attr.arrayDimensions = &arrayDimensions[0]; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); +attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2371), -UA_NODEID_NUMERIC(ns[0], 2368), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "EngineeringUnits"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2377LU), +UA_NODEID_NUMERIC(ns[0], 2376LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "EnumStrings"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_60_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_58_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2371) +UA_NODEID_NUMERIC(ns[0], 2377LU) ); } -/* EURange - ns=0;i=2369 */ +/* TwoStateDiscreteType - ns=0;i=2373 */ -static UA_StatusCode function_namespace0_generated_61_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_59_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 3; -attr.accessLevel = 3; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 884); -attr.displayName = UA_LOCALIZEDTEXT("", "EURange"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2369), -UA_NODEID_NUMERIC(ns[0], 2368), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "EURange"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "TwoStateDiscreteType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 2373LU), +UA_NODEID_NUMERIC(ns[0], 2372LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "TwoStateDiscreteType"), +UA_NODEID_NUMERIC(ns[0], 0LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_61_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_59_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2369) +UA_NODEID_NUMERIC(ns[0], 2373LU) ); } -/* ValuePrecision - ns=0;i=2367 */ +/* TrueState - ns=0;i=2375 */ -static UA_StatusCode function_namespace0_generated_62_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_60_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 11); -attr.displayName = UA_LOCALIZEDTEXT("", "ValuePrecision"); -#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS -attr.description = UA_LOCALIZEDTEXT("", "The maximum precision that the server can maintain for the item based on restrictions in the target environment."); -#endif +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); +attr.displayName = UA_LOCALIZEDTEXT("", "TrueState"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2367), -UA_NODEID_NUMERIC(ns[0], 2365), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "ValuePrecision"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2375LU), +UA_NODEID_NUMERIC(ns[0], 2373LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "TrueState"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_62_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_60_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2367) +UA_NODEID_NUMERIC(ns[0], 2375LU) ); } -/* DiscreteItemType - ns=0;i=2372 */ +/* FalseState - ns=0;i=2374 */ -static UA_StatusCode function_namespace0_generated_63_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_61_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; -attr.isAbstract = true; +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ attr.valueRank = -2; -/* DataType inherited */ -attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); -attr.displayName = UA_LOCALIZEDTEXT("", "DiscreteItemType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2372), -UA_NODEID_NUMERIC(ns[0], 2365), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "DiscreteItemType"), -UA_NODEID_NUMERIC(ns[0], 0), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); +attr.displayName = UA_LOCALIZEDTEXT("", "FalseState"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2374LU), +UA_NODEID_NUMERIC(ns[0], 2373LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "FalseState"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_63_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_61_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2372) +UA_NODEID_NUMERIC(ns[0], 2374LU) ); } /* MultiStateValueDiscreteType - ns=0;i=11238 */ -static UA_StatusCode function_namespace0_generated_64_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_62_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; attr.valueRank = -2; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 26); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 26LU); attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateValueDiscreteType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 11238), -UA_NODEID_NUMERIC(ns[0], 2372), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 11238LU), +UA_NODEID_NUMERIC(ns[0], 2372LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "MultiStateValueDiscreteType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_64_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_62_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11238) +UA_NODEID_NUMERIC(ns[0], 11238LU) ); } /* ValueAsText - ns=0;i=11461 */ -static UA_StatusCode function_namespace0_generated_65_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_63_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); attr.displayName = UA_LOCALIZEDTEXT("", "ValueAsText"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11461), -UA_NODEID_NUMERIC(ns[0], 11238), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 11461LU), +UA_NODEID_NUMERIC(ns[0], 11238LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "ValueAsText"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_65_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_63_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11461) +UA_NODEID_NUMERIC(ns[0], 11461LU) ); } /* EnumValues - ns=0;i=11241 */ -static UA_StatusCode function_namespace0_generated_66_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_64_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; @@ -47850,586 +53507,637 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594LU); attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11241), -UA_NODEID_NUMERIC(ns[0], 11238), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 11241LU), +UA_NODEID_NUMERIC(ns[0], 11238LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "EnumValues"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_66_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_64_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11241) +UA_NODEID_NUMERIC(ns[0], 11241LU) ); } -/* MultiStateDiscreteType - ns=0;i=2376 */ +/* AnalogItemType - ns=0;i=2368 */ -static UA_StatusCode function_namespace0_generated_67_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_65_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; attr.valueRank = -2; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 28); -attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateDiscreteType"); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 26LU); +attr.displayName = UA_LOCALIZEDTEXT("", "AnalogItemType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2376), -UA_NODEID_NUMERIC(ns[0], 2372), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "MultiStateDiscreteType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 2368LU), +UA_NODEID_NUMERIC(ns[0], 2365LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "AnalogItemType"), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_67_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_65_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2376) +UA_NODEID_NUMERIC(ns[0], 2368LU) ); } -/* EnumStrings - ns=0;i=2377 */ +/* EngineeringUnits - ns=0;i=2371 */ -static UA_StatusCode function_namespace0_generated_68_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_66_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -attr.valueRank = 1; -attr.arrayDimensionsSize = 1; -UA_UInt32 arrayDimensions[1]; -arrayDimensions[0] = 0; -attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); -attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings"); +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 887LU); +attr.displayName = UA_LOCALIZEDTEXT("", "EngineeringUnits"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2377), -UA_NODEID_NUMERIC(ns[0], 2376), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "EnumStrings"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2371LU), +UA_NODEID_NUMERIC(ns[0], 2368LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "EngineeringUnits"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_68_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_66_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2377) +UA_NODEID_NUMERIC(ns[0], 2371LU) ); } -/* TwoStateDiscreteType - ns=0;i=2373 */ +/* InstrumentRange - ns=0;i=2370 */ -static UA_StatusCode function_namespace0_generated_69_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_67_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ attr.valueRank = -2; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "TwoStateDiscreteType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2373), -UA_NODEID_NUMERIC(ns[0], 2372), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "TwoStateDiscreteType"), -UA_NODEID_NUMERIC(ns[0], 0), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 884LU); +attr.displayName = UA_LOCALIZEDTEXT("", "InstrumentRange"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2370LU), +UA_NODEID_NUMERIC(ns[0], 2368LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "InstrumentRange"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_69_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_67_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2373) +UA_NODEID_NUMERIC(ns[0], 2370LU) ); } -/* FalseState - ns=0;i=2374 */ +/* EURange - ns=0;i=2369 */ -static UA_StatusCode function_namespace0_generated_70_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_68_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; +attr.userAccessLevel = 3; +attr.accessLevel = 3; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); -attr.displayName = UA_LOCALIZEDTEXT("", "FalseState"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 884LU); +attr.displayName = UA_LOCALIZEDTEXT("", "EURange"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2374), -UA_NODEID_NUMERIC(ns[0], 2373), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "FalseState"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2369LU), +UA_NODEID_NUMERIC(ns[0], 2368LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "EURange"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_70_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_68_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2374) +UA_NODEID_NUMERIC(ns[0], 2369LU) ); } -/* TrueState - ns=0;i=2375 */ +/* ValuePrecision - ns=0;i=2367 */ -static UA_StatusCode function_namespace0_generated_71_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_69_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); -attr.displayName = UA_LOCALIZEDTEXT("", "TrueState"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 11LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ValuePrecision"); +#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS +attr.description = UA_LOCALIZEDTEXT("", "The maximum precision that the server can maintain for the item based on restrictions in the target environment."); +#endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2375), -UA_NODEID_NUMERIC(ns[0], 2373), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "TrueState"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2367LU), +UA_NODEID_NUMERIC(ns[0], 2365LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "ValuePrecision"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_71_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_69_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2375) +UA_NODEID_NUMERIC(ns[0], 2367LU) ); } /* Definition - ns=0;i=2366 */ -static UA_StatusCode function_namespace0_generated_72_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_70_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); attr.displayName = UA_LOCALIZEDTEXT("", "Definition"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "A vendor-specific, human readable string that specifies how the value of this DataItem is calculated."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2366), -UA_NODEID_NUMERIC(ns[0], 2365), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2366LU), +UA_NODEID_NUMERIC(ns[0], 2365LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "Definition"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_72_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_70_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2366) +UA_NODEID_NUMERIC(ns[0], 2366LU) ); } /* HistoryServerCapabilitiesType - ns=0;i=2330 */ -static UA_StatusCode function_namespace0_generated_73_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_71_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilitiesType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 2330), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 2330LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "HistoryServerCapabilitiesType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_73_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_71_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2330) +UA_NODEID_NUMERIC(ns[0], 2330LU) ); } /* EventQueueOverflowEventType - ns=0;i=3035 */ -static UA_StatusCode function_namespace0_generated_74_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_72_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.isAbstract = true; attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowEventType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 3035), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 3035LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "EventQueueOverflowEventType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_74_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_72_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3035) +UA_NODEID_NUMERIC(ns[0], 3035LU) ); } /* Severity - ns=0;i=2051 */ -static UA_StatusCode function_namespace0_generated_75_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_73_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 5); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU); attr.displayName = UA_LOCALIZEDTEXT("", "Severity"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "Indicates how urgent an event is."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2051), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2051LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "Severity"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_75_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_73_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2051) +UA_NODEID_NUMERIC(ns[0], 2051LU) ); } /* Message - ns=0;i=2050 */ -static UA_StatusCode function_namespace0_generated_76_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_74_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); attr.displayName = UA_LOCALIZEDTEXT("", "Message"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "A localized description of the event."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2050), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2050LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "Message"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_76_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_74_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2050) +UA_NODEID_NUMERIC(ns[0], 2050LU) ); } /* LocalTime - ns=0;i=3190 */ -static UA_StatusCode function_namespace0_generated_77_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_75_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 8912); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 8912LU); attr.displayName = UA_LOCALIZEDTEXT("", "LocalTime"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "Information about the local time where the event originated."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 3190), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 3190LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "LocalTime"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_77_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_75_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3190) +UA_NODEID_NUMERIC(ns[0], 3190LU) ); } /* ReceiveTime - ns=0;i=2047 */ -static UA_StatusCode function_namespace0_generated_78_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_76_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 294); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU); attr.displayName = UA_LOCALIZEDTEXT("", "ReceiveTime"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "When the server received the event from the underlying system."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2047), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2047LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "ReceiveTime"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_78_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_76_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2047) +UA_NODEID_NUMERIC(ns[0], 2047LU) ); } /* Time - ns=0;i=2046 */ -static UA_StatusCode function_namespace0_generated_79_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_77_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 294); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU); attr.displayName = UA_LOCALIZEDTEXT("", "Time"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "When the event occurred."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2046), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2046LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "Time"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_79_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_77_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2046) +UA_NODEID_NUMERIC(ns[0], 2046LU) ); } /* SourceName - ns=0;i=2045 */ -static UA_StatusCode function_namespace0_generated_80_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_78_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); attr.displayName = UA_LOCALIZEDTEXT("", "SourceName"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "A description of the source of the event."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2045), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2045LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "SourceName"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_80_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_78_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2045) +UA_NODEID_NUMERIC(ns[0], 2045LU) ); } /* SourceNode - ns=0;i=2044 */ -static UA_StatusCode function_namespace0_generated_81_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_79_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 17); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU); attr.displayName = UA_LOCALIZEDTEXT("", "SourceNode"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "The source of the event."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2044), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2044LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "SourceNode"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_81_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_79_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2044) +UA_NODEID_NUMERIC(ns[0], 2044LU) ); } /* EventType - ns=0;i=2043 */ -static UA_StatusCode function_namespace0_generated_82_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_80_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 17); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU); attr.displayName = UA_LOCALIZEDTEXT("", "EventType"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "The identifier for the event type."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2043), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2043LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "EventType"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_82_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_80_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2043) +UA_NODEID_NUMERIC(ns[0], 2043LU) ); } /* EventId - ns=0;i=2042 */ -static UA_StatusCode function_namespace0_generated_83_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_81_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 15); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU); attr.displayName = UA_LOCALIZEDTEXT("", "EventId"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "A globally unique identifier for the event."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2042), -UA_NODEID_NUMERIC(ns[0], 2041), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 2042LU), +UA_NODEID_NUMERIC(ns[0], 2041LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "EventId"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_83_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_81_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2042) +UA_NODEID_NUMERIC(ns[0], 2042LU) ); } /* InterfaceTypes - ns=0;i=17708 */ -static UA_StatusCode function_namespace0_generated_84_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_82_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "InterfaceTypes"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 17708), -UA_NODEID_NUMERIC(ns[0], 86), -UA_NODEID_NUMERIC(ns[0], 35), +UA_NODEID_NUMERIC(ns[0], 17708LU), +UA_NODEID_NUMERIC(ns[0], 86LU), +UA_NODEID_NUMERIC(ns[0], 35LU), UA_QUALIFIEDNAME(ns[0], "InterfaceTypes"), -UA_NODEID_NUMERIC(ns[0], 61), +UA_NODEID_NUMERIC(ns[0], 61LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_84_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_82_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 17708) +UA_NODEID_NUMERIC(ns[0], 17708LU) ); } /* BaseInterfaceType - ns=0;i=17602 */ -static UA_StatusCode function_namespace0_generated_85_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_83_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.isAbstract = true; attr.displayName = UA_LOCALIZEDTEXT("", "BaseInterfaceType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 17602), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 17602LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "BaseInterfaceType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 17602), UA_NODEID_NUMERIC(ns[0], 35), UA_EXPANDEDNODEID_NUMERIC(ns[0], 17708), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 17602LU), UA_NODEID_NUMERIC(ns[0], 35LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 17708LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_85_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_83_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 17602) +UA_NODEID_NUMERIC(ns[0], 17602LU) ); } -/* ServerDiagnosticsSummaryType - ns=0;i=2150 */ +/* BuildInfoType - ns=0;i=3051 */ -static UA_StatusCode function_namespace0_generated_86_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_84_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 859); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryType"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 338LU); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfoType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 63), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummaryType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 3051LU), +UA_NODEID_NUMERIC(ns[0], 63LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "BuildInfoType"), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } +static UA_StatusCode function_namespace0_generated_84_finish(UA_Server *server, UA_UInt16* ns) { +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3051LU) +); +} + +/* ServerStatusType - ns=0;i=2138 */ + +static UA_StatusCode function_namespace0_generated_85_begin(UA_Server *server, UA_UInt16* ns) { +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 862LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 2138LU), +UA_NODEID_NUMERIC(ns[0], 63LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerStatusType"), +UA_NODEID_NUMERIC(ns[0], 0LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +return retVal; +} + +static UA_StatusCode function_namespace0_generated_85_finish(UA_Server *server, UA_UInt16* ns) { +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2138LU) +); +} + +/* OperationLimitsType - ns=0;i=11564 */ + +static UA_StatusCode function_namespace0_generated_86_begin(UA_Server *server, UA_UInt16* ns) { +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimitsType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 61LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "OperationLimitsType"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +return retVal; +} + static UA_StatusCode function_namespace0_generated_86_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2150) +UA_NODEID_NUMERIC(ns[0], 11564LU) ); } -/* PublishingIntervalCount - ns=0;i=2159 */ +/* MaxMonitoredItemsPerCall - ns=0;i=11574 */ static UA_StatusCode function_namespace0_generated_87_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48438,26 +54146,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2159), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11574LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_87_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2159) +UA_NODEID_NUMERIC(ns[0], 11574LU) ); } -/* SecurityRejectedSessionCount - ns=0;i=2154 */ +/* MaxNodesPerNodeManagement - ns=0;i=11573 */ static UA_StatusCode function_namespace0_generated_88_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48466,26 +54174,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2154), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11573LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_88_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2154) +UA_NODEID_NUMERIC(ns[0], 11573LU) ); } -/* SessionAbortCount - ns=0;i=2157 */ +/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11572 */ static UA_StatusCode function_namespace0_generated_89_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48494,26 +54202,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2157), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11572LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_89_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2157) +UA_NODEID_NUMERIC(ns[0], 11572LU) ); } -/* ServerViewCount - ns=0;i=2151 */ +/* MaxNodesPerRegisterNodes - ns=0;i=11571 */ static UA_StatusCode function_namespace0_generated_90_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48522,26 +54230,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2151), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerViewCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11571LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_90_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2151) +UA_NODEID_NUMERIC(ns[0], 11571LU) ); } -/* RejectedRequestsCount - ns=0;i=2163 */ +/* MaxNodesPerBrowse - ns=0;i=11570 */ static UA_StatusCode function_namespace0_generated_91_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48550,26 +54258,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2163), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11570LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_91_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2163) +UA_NODEID_NUMERIC(ns[0], 11570LU) ); } -/* SessionTimeoutCount - ns=0;i=2156 */ +/* MaxNodesPerMethodCall - ns=0;i=11569 */ static UA_StatusCode function_namespace0_generated_92_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48578,26 +54286,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2156), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11569LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_92_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2156) +UA_NODEID_NUMERIC(ns[0], 11569LU) ); } -/* CurrentSessionCount - ns=0;i=2152 */ +/* MaxNodesPerWrite - ns=0;i=11567 */ static UA_StatusCode function_namespace0_generated_93_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48606,26 +54314,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2152), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11567LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_93_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2152) +UA_NODEID_NUMERIC(ns[0], 11567LU) ); } -/* CumulatedSubscriptionCount - ns=0;i=2161 */ +/* MaxNodesPerRead - ns=0;i=11565 */ static UA_StatusCode function_namespace0_generated_94_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48634,54 +54342,48 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2161), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11565LU), +UA_NODEID_NUMERIC(ns[0], 11564LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_94_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2161) +UA_NODEID_NUMERIC(ns[0], 11565LU) ); } -/* SecurityRejectedRequestsCount - ns=0;i=2162 */ +/* ServerRedundancyType - ns=0;i=2034 */ static UA_StatusCode function_namespace0_generated_95_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2162), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"), -UA_NODEID_NUMERIC(ns[0], 63), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancyType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2034LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerRedundancyType"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_95_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2162) +UA_NODEID_NUMERIC(ns[0], 2034LU) ); } -/* CumulatedSessionCount - ns=0;i=2153 */ +/* RedundancySupport - ns=0;i=2035 */ static UA_StatusCode function_namespace0_generated_96_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48690,142 +54392,124 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 851LU); +attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2153), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2035LU), +UA_NODEID_NUMERIC(ns[0], 2034LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_96_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2153) +UA_NODEID_NUMERIC(ns[0], 2035LU) ); } -/* CurrentSubscriptionCount - ns=0;i=2160 */ +/* VendorServerInfoType - ns=0;i=2033 */ static UA_StatusCode function_namespace0_generated_97_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2160), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"), -UA_NODEID_NUMERIC(ns[0], 63), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfoType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2033LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "VendorServerInfoType"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_97_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2160) +UA_NODEID_NUMERIC(ns[0], 2033LU) ); } -/* RejectedSessionCount - ns=0;i=2155 */ +/* ServerDiagnosticsType - ns=0;i=2020 */ static UA_StatusCode function_namespace0_generated_98_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2155), -UA_NODEID_NUMERIC(ns[0], 2150), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2020LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsType"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_98_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2155) +UA_NODEID_NUMERIC(ns[0], 2020LU) ); } -/* BuildInfoType - ns=0;i=3051 */ +/* ServerCapabilitiesType - ns=0;i=2013 */ static UA_StatusCode function_namespace0_generated_99_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 338); -attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfoType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 3051), -UA_NODEID_NUMERIC(ns[0], 63), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "BuildInfoType"), -UA_NODEID_NUMERIC(ns[0], 0), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilitiesType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2013LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerCapabilitiesType"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_99_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3051) +UA_NODEID_NUMERIC(ns[0], 2013LU) ); } -/* ServerStatusType - ns=0;i=2138 */ +/* OperationLimits - ns=0;i=11551 */ static UA_StatusCode function_namespace0_generated_100_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 862); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 2138), -UA_NODEID_NUMERIC(ns[0], 63), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerStatusType"), -UA_NODEID_NUMERIC(ns[0], 0), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 11551LU), +UA_NODEID_NUMERIC(ns[0], 2013LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "OperationLimits"), +UA_NODEID_NUMERIC(ns[0], 11564LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_100_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2138) +UA_NODEID_NUMERIC(ns[0], 11551LU) ); } -/* OperationLimitsType - ns=0;i=11564 */ +/* ServerType - ns=0;i=2004 */ static UA_StatusCode function_namespace0_generated_101_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimitsType"); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 61), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "OperationLimitsType"), +UA_NODEID_NUMERIC(ns[0], 2004LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ServerType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; @@ -48833,95 +54517,84 @@ return retVal; static UA_StatusCode function_namespace0_generated_101_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11564) +UA_NODEID_NUMERIC(ns[0], 2004LU) ); } -/* MaxNodesPerMethodCall - ns=0;i=11569 */ +/* Server - ns=0;i=2253 */ static UA_StatusCode function_namespace0_generated_102_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11569), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.eventNotifier = UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT; +attr.displayName = UA_LOCALIZEDTEXT("", "Server"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 85LU), +UA_NODEID_NUMERIC(ns[0], 35LU), +UA_QUALIFIEDNAME(ns[0], "Server"), +UA_NODEID_NUMERIC(ns[0], 2004LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_102_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11569) +UA_NODEID_NUMERIC(ns[0], 2253LU) ); } -/* MaxNodesPerWrite - ns=0;i=11567 */ +/* Auditing - ns=0;i=2994 */ static UA_StatusCode function_namespace0_generated_103_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "Auditing"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11567), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2994LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "Auditing"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_103_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11567) +UA_NODEID_NUMERIC(ns[0], 2994LU) ); } -/* MaxNodesPerRead - ns=0;i=11565 */ +/* ServerRedundancy - ns=0;i=2296 */ static UA_StatusCode function_namespace0_generated_104_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11565), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancy"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2296LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ServerRedundancy"), +UA_NODEID_NUMERIC(ns[0], 2034LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_104_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11565) +UA_NODEID_NUMERIC(ns[0], 2296LU) ); } -/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11572 */ +/* RedundancySupport - ns=0;i=3709 */ static UA_StatusCode function_namespace0_generated_105_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -48930,462 +54603,475 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 851LU); +attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11572), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 3709LU), +UA_NODEID_NUMERIC(ns[0], 2296LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_105_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11572) +UA_NODEID_NUMERIC(ns[0], 3709LU) ); } -/* MaxMonitoredItemsPerCall - ns=0;i=11574 */ +/* VendorServerInfo - ns=0;i=2295 */ static UA_StatusCode function_namespace0_generated_106_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11574), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2295LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"), +UA_NODEID_NUMERIC(ns[0], 2033LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_106_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11574) +UA_NODEID_NUMERIC(ns[0], 2295LU) ); } -/* MaxNodesPerRegisterNodes - ns=0;i=11571 */ +/* ServerDiagnostics - ns=0;i=2274 */ static UA_StatusCode function_namespace0_generated_107_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11571), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnostics"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2274LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnostics"), +UA_NODEID_NUMERIC(ns[0], 2020LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_107_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11571) +UA_NODEID_NUMERIC(ns[0], 2274LU) ); } -/* MaxNodesPerNodeManagement - ns=0;i=11573 */ +/* EnabledFlag - ns=0;i=2294 */ static UA_StatusCode function_namespace0_generated_108_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; -attr.accessLevel = 1; +attr.accessLevel = 3; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11573), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2294LU), +UA_NODEID_NUMERIC(ns[0], 2274LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "EnabledFlag"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_108_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11573) +UA_NODEID_NUMERIC(ns[0], 2294LU) ); } -/* MaxNodesPerBrowse - ns=0;i=11570 */ +/* ServerCapabilities - ns=0;i=2268 */ static UA_StatusCode function_namespace0_generated_109_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11570), -UA_NODEID_NUMERIC(ns[0], 11564), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilities"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ServerCapabilities"), +UA_NODEID_NUMERIC(ns[0], 2013LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_109_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11570) +UA_NODEID_NUMERIC(ns[0], 2268LU) ); } -/* ServerRedundancyType - ns=0;i=2034 */ +/* SoftwareCertificates - ns=0;i=3704 */ static UA_StatusCode function_namespace0_generated_110_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancyType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 2034), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerRedundancyType"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +attr.valueRank = 1; +attr.arrayDimensionsSize = 1; +UA_UInt32 arrayDimensions[1]; +arrayDimensions[0] = 0; +attr.arrayDimensions = &arrayDimensions[0]; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 344LU); +attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareCertificates"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 3704LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "SoftwareCertificates"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_110_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2034) +UA_NODEID_NUMERIC(ns[0], 3704LU) ); } -/* RedundancySupport - ns=0;i=2035 */ +/* AggregateFunctions - ns=0;i=2997 */ static UA_StatusCode function_namespace0_generated_111_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 851); -attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2035), -UA_NODEID_NUMERIC(ns[0], 2034), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2997LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"), +UA_NODEID_NUMERIC(ns[0], 61LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_111_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2035) +UA_NODEID_NUMERIC(ns[0], 2997LU) ); } -/* VendorServerInfoType - ns=0;i=2033 */ +/* ModellingRules - ns=0;i=2996 */ static UA_StatusCode function_namespace0_generated_112_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfoType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 2033), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "VendorServerInfoType"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRules"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2996LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ModellingRules"), +UA_NODEID_NUMERIC(ns[0], 61LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_112_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2033) +UA_NODEID_NUMERIC(ns[0], 2996LU) ); } -/* ServerDiagnosticsType - ns=0;i=2020 */ +/* MaxHistoryContinuationPoints - ns=0;i=2737 */ static UA_StatusCode function_namespace0_generated_113_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 2020), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsType"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxHistoryContinuationPoints"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2737LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxHistoryContinuationPoints"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_113_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2020) +UA_NODEID_NUMERIC(ns[0], 2737LU) ); } -/* ServerCapabilitiesType - ns=0;i=2013 */ +/* MaxQueryContinuationPoints - ns=0;i=2736 */ static UA_StatusCode function_namespace0_generated_114_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilitiesType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 2013), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerCapabilitiesType"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxQueryContinuationPoints"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2736LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxQueryContinuationPoints"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_114_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2013) +UA_NODEID_NUMERIC(ns[0], 2736LU) ); } -/* OperationLimits - ns=0;i=11551 */ +/* MaxBrowseContinuationPoints - ns=0;i=2735 */ static UA_StatusCode function_namespace0_generated_115_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 11551), -UA_NODEID_NUMERIC(ns[0], 2013), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "OperationLimits"), -UA_NODEID_NUMERIC(ns[0], 11564), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxBrowseContinuationPoints"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2735LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxBrowseContinuationPoints"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_115_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11551) +UA_NODEID_NUMERIC(ns[0], 2735LU) ); } -/* ServerType - ns=0;i=2004 */ +/* MinSupportedSampleRate - ns=0;i=2272 */ static UA_StatusCode function_namespace0_generated_116_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 2004), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ServerType"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MinSupportedSampleRate"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2272LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MinSupportedSampleRate"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_116_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2004) +UA_NODEID_NUMERIC(ns[0], 2272LU) ); } -/* Server - ns=0;i=2253 */ +/* LocaleIdArray - ns=0;i=2271 */ static UA_StatusCode function_namespace0_generated_117_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.eventNotifier = true; -attr.displayName = UA_LOCALIZEDTEXT("", "Server"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 85), -UA_NODEID_NUMERIC(ns[0], 35), -UA_QUALIFIEDNAME(ns[0], "Server"), -UA_NODEID_NUMERIC(ns[0], 2004), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +attr.valueRank = 1; +attr.arrayDimensionsSize = 1; +UA_UInt32 arrayDimensions[1]; +arrayDimensions[0] = 0; +attr.arrayDimensions = &arrayDimensions[0]; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 295LU); +attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIdArray"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2271LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "LocaleIdArray"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_117_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2253) +UA_NODEID_NUMERIC(ns[0], 2271LU) ); } -/* Auditing - ns=0;i=2994 */ +/* ServerProfileArray - ns=0;i=2269 */ static UA_StatusCode function_namespace0_generated_118_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "Auditing"); +attr.valueRank = 1; +attr.arrayDimensionsSize = 1; +UA_UInt32 arrayDimensions[1]; +arrayDimensions[0] = 0; +attr.arrayDimensions = &arrayDimensions[0]; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerProfileArray"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2994), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "Auditing"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2269LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "ServerProfileArray"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_118_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2994) +UA_NODEID_NUMERIC(ns[0], 2269LU) ); } -/* ServiceLevel - ns=0;i=2267 */ +/* OperationLimits - ns=0;i=11704 */ static UA_StatusCode function_namespace0_generated_119_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 3); -attr.displayName = UA_LOCALIZEDTEXT("", "ServiceLevel"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2267), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "ServiceLevel"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "OperationLimits"), +UA_NODEID_NUMERIC(ns[0], 11564LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_119_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2267) +UA_NODEID_NUMERIC(ns[0], 11704LU) ); } -/* VendorServerInfo - ns=0;i=2295 */ +/* MaxMonitoredItemsPerCall - ns=0;i=11714 */ static UA_StatusCode function_namespace0_generated_120_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2295), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"), -UA_NODEID_NUMERIC(ns[0], 2033), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11714LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_120_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2295) +UA_NODEID_NUMERIC(ns[0], 11714LU) ); } -/* NamespaceArray - ns=0;i=2255 */ +/* MaxNodesPerNodeManagement - ns=0;i=11713 */ static UA_StatusCode function_namespace0_generated_121_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -attr.valueRank = 1; -attr.arrayDimensionsSize = 1; -UA_UInt32 arrayDimensions[1]; -arrayDimensions[0] = 0; -attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceArray"); +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2255), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "NamespaceArray"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 11713LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_121_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2255) +UA_NODEID_NUMERIC(ns[0], 11713LU) ); } -/* GetMonitoredItems - ns=0;i=11492 */ +/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11712 */ static UA_StatusCode function_namespace0_generated_122_begin(UA_Server *server, UA_UInt16* ns) { -#ifdef UA_ENABLE_METHODCALLS UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_MethodAttributes attr = UA_MethodAttributes_default; -attr.executable = true; -attr.userExecutable = true; -attr.displayName = UA_LOCALIZEDTEXT("", "GetMonitoredItems"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD, -UA_NODEID_NUMERIC(ns[0], 11492), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "GetMonitoredItems"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11712LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; -#else -return UA_STATUSCODE_GOOD; -#endif /* UA_ENABLE_METHODCALLS */ } static UA_StatusCode function_namespace0_generated_122_finish(UA_Server *server, UA_UInt16* ns) { -#ifdef UA_ENABLE_METHODCALLS -return UA_Server_addMethodNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11492) -, NULL, 0, NULL, 0, NULL); -#else -return UA_STATUSCODE_GOOD; -#endif /* UA_ENABLE_METHODCALLS */ +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11712LU) +); } -/* OutputArguments - ns=0;i=11494 */ +/* MaxNodesPerRegisterNodes - ns=0;i=11711 */ static UA_StatusCode function_namespace0_generated_123_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49393,54 +55079,27 @@ UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -attr.valueRank = 1; -attr.arrayDimensionsSize = 1; -UA_UInt32 arrayDimensions[1]; -arrayDimensions[0] = 0; -attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 296); -UA_Argument variablenode_ns_0_i_11494_variant_DataContents[2]; - -UA_init(&variablenode_ns_0_i_11494_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]); -variablenode_ns_0_i_11494_variant_DataContents[0].name = UA_STRING("ServerHandles"); -variablenode_ns_0_i_11494_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7); -variablenode_ns_0_i_11494_variant_DataContents[0].valueRank = (UA_Int32) 1; -UA_STACKARRAY(UA_UInt32, variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions, 1); -UA_init(variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]); -variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions[0] = (UA_UInt32) 0; -variablenode_ns_0_i_11494_variant_DataContents[0].arrayDimensionsSize = 1; -variablenode_ns_0_i_11494_variant_DataContents[0].arrayDimensions = variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions; - -UA_init(&variablenode_ns_0_i_11494_variant_DataContents[1], &UA_TYPES[UA_TYPES_ARGUMENT]); -variablenode_ns_0_i_11494_variant_DataContents[1].name = UA_STRING("ClientHandles"); -variablenode_ns_0_i_11494_variant_DataContents[1].dataType = UA_NODEID_NUMERIC(ns[0], 7); -variablenode_ns_0_i_11494_variant_DataContents[1].valueRank = (UA_Int32) 1; -UA_STACKARRAY(UA_UInt32, variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions, 1); -UA_init(variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]); -variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions[0] = (UA_UInt32) 0; -variablenode_ns_0_i_11494_variant_DataContents[1].arrayDimensionsSize = 1; -variablenode_ns_0_i_11494_variant_DataContents[1].arrayDimensions = variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions; -UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11494_variant_DataContents, (UA_Int32) 2, &UA_TYPES[UA_TYPES_ARGUMENT]); -attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments"); +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11494), -UA_NODEID_NUMERIC(ns[0], 11492), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "OutputArguments"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 11711LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); - - return retVal; } static UA_StatusCode function_namespace0_generated_123_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11494) +UA_NODEID_NUMERIC(ns[0], 11711LU) ); } -/* InputArguments - ns=0;i=11493 */ +/* MaxNodesPerBrowse - ns=0;i=11710 */ static UA_StatusCode function_namespace0_generated_124_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49448,66 +55107,55 @@ UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -attr.valueRank = 1; -attr.arrayDimensionsSize = 1; -UA_UInt32 arrayDimensions[1]; -arrayDimensions[0] = 0; -attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 296); -UA_Argument variablenode_ns_0_i_11493_variant_DataContents[1]; - -UA_init(&variablenode_ns_0_i_11493_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]); -variablenode_ns_0_i_11493_variant_DataContents[0].name = UA_STRING("SubscriptionId"); -variablenode_ns_0_i_11493_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7); -variablenode_ns_0_i_11493_variant_DataContents[0].valueRank = (UA_Int32) -1; -UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11493_variant_DataContents, (UA_Int32) 1, &UA_TYPES[UA_TYPES_ARGUMENT]); -attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments"); +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11493), -UA_NODEID_NUMERIC(ns[0], 11492), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "InputArguments"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 11710LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); - return retVal; } static UA_StatusCode function_namespace0_generated_124_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11493) +UA_NODEID_NUMERIC(ns[0], 11710LU) ); } -/* ServerStatus - ns=0;i=2256 */ +/* MaxNodesPerMethodCall - ns=0;i=11709 */ static UA_StatusCode function_namespace0_generated_125_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 862); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatus"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerStatus"), -UA_NODEID_NUMERIC(ns[0], 2138), +UA_NODEID_NUMERIC(ns[0], 11709LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_125_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2256) +UA_NODEID_NUMERIC(ns[0], 11709LU) ); } -/* ShutdownReason - ns=0;i=2993 */ +/* MaxNodesPerWrite - ns=0;i=11707 */ static UA_StatusCode function_namespace0_generated_126_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49516,26 +55164,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); -attr.displayName = UA_LOCALIZEDTEXT("", "ShutdownReason"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2993), -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ShutdownReason"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11707LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_126_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2993) +UA_NODEID_NUMERIC(ns[0], 11707LU) ); } -/* BuildInfo - ns=0;i=2260 */ +/* MaxNodesPerRead - ns=0;i=11705 */ static UA_StatusCode function_namespace0_generated_127_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49544,194 +55192,188 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 338); -attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "BuildInfo"), -UA_NODEID_NUMERIC(ns[0], 3051), +UA_NODEID_NUMERIC(ns[0], 11705LU), +UA_NODEID_NUMERIC(ns[0], 11704LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_127_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2260) +UA_NODEID_NUMERIC(ns[0], 11705LU) ); } -/* ProductUri - ns=0;i=2262 */ +/* HistoryServerCapabilities - ns=0;i=11192 */ static UA_StatusCode function_namespace0_generated_128_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "ProductUri"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2262), -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ProductUri"), -UA_NODEID_NUMERIC(ns[0], 63), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilities"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 2268LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "HistoryServerCapabilities"), +UA_NODEID_NUMERIC(ns[0], 2330LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_128_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2262) +UA_NODEID_NUMERIC(ns[0], 11192LU) ); } -/* ProductName - ns=0;i=2261 */ +/* DeleteEventCapability - ns=0;i=11502 */ static UA_StatusCode function_namespace0_generated_129_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "ProductName"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "DeleteEventCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2261), -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ProductName"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11502LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "DeleteEventCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_129_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2261) +UA_NODEID_NUMERIC(ns[0], 11502LU) ); } -/* BuildDate - ns=0;i=2266 */ +/* UpdateEventCapability - ns=0;i=11283 */ static UA_StatusCode function_namespace0_generated_130_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 294); -attr.displayName = UA_LOCALIZEDTEXT("", "BuildDate"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "UpdateEventCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2266), -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "BuildDate"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11283LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "UpdateEventCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_130_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2266) +UA_NODEID_NUMERIC(ns[0], 11283LU) ); } -/* BuildNumber - ns=0;i=2265 */ +/* ReplaceEventCapability - ns=0;i=11282 */ static UA_StatusCode function_namespace0_generated_131_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "BuildNumber"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceEventCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2265), -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "BuildNumber"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11282LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "ReplaceEventCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_131_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2265) +UA_NODEID_NUMERIC(ns[0], 11282LU) ); } -/* ManufacturerName - ns=0;i=2263 */ +/* InsertEventCapability - ns=0;i=11281 */ static UA_StatusCode function_namespace0_generated_132_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "ManufacturerName"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "InsertEventCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2263), -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ManufacturerName"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11281LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "InsertEventCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_132_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2263) +UA_NODEID_NUMERIC(ns[0], 11281LU) ); } -/* SoftwareVersion - ns=0;i=2264 */ +/* InsertAnnotationCapability - ns=0;i=11275 */ static UA_StatusCode function_namespace0_generated_133_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 1000.000000; +attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareVersion"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "InsertAnnotationCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2264), -UA_NODEID_NUMERIC(ns[0], 2260), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SoftwareVersion"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11275LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "InsertAnnotationCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_133_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2264) +UA_NODEID_NUMERIC(ns[0], 11275LU) ); } -/* SecondsTillShutdown - ns=0;i=2992 */ +/* MaxReturnEventValues - ns=0;i=11274 */ static UA_StatusCode function_namespace0_generated_134_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49740,26 +55382,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SecondsTillShutdown"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnEventValues"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2992), -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SecondsTillShutdown"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11274LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxReturnEventValues"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_134_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2992) +UA_NODEID_NUMERIC(ns[0], 11274LU) ); } -/* StartTime - ns=0;i=2257 */ +/* MaxReturnDataValues - ns=0;i=11273 */ static UA_StatusCode function_namespace0_generated_135_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49768,26 +55410,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 294); -attr.displayName = UA_LOCALIZEDTEXT("", "StartTime"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnDataValues"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2257), -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "StartTime"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11273LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "MaxReturnDataValues"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_135_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2257) +UA_NODEID_NUMERIC(ns[0], 11273LU) ); } -/* CurrentTime - ns=0;i=2258 */ +/* AccessHistoryEventsCapability - ns=0;i=11242 */ static UA_StatusCode function_namespace0_generated_136_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49796,76 +55438,76 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 294); -attr.displayName = UA_LOCALIZEDTEXT("", "CurrentTime"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryEventsCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2258), -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CurrentTime"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11242LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "AccessHistoryEventsCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_136_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2258) +UA_NODEID_NUMERIC(ns[0], 11242LU) ); } -/* State - ns=0;i=2259 */ +/* AggregateFunctions - ns=0;i=11201 */ static UA_StatusCode function_namespace0_generated_137_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 852); -attr.displayName = UA_LOCALIZEDTEXT("", "State"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2259), -UA_NODEID_NUMERIC(ns[0], 2256), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "State"), -UA_NODEID_NUMERIC(ns[0], 63), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 11201LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"), +UA_NODEID_NUMERIC(ns[0], 61LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_137_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2259) +UA_NODEID_NUMERIC(ns[0], 11201LU) ); } -/* ServerDiagnostics - ns=0;i=2274 */ +/* DeleteAtTimeCapability - ns=0;i=11200 */ static UA_StatusCode function_namespace0_generated_138_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnostics"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2274), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerDiagnostics"), -UA_NODEID_NUMERIC(ns[0], 2020), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +UA_VariableAttributes attr = UA_VariableAttributes_default; +attr.minimumSamplingInterval = 0.000000; +attr.userAccessLevel = 1; +attr.accessLevel = 1; +/* Value rank inherited */ +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "DeleteAtTimeCapability"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11200LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "DeleteAtTimeCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_138_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2274) +UA_NODEID_NUMERIC(ns[0], 11200LU) ); } -/* ServerDiagnosticsSummary - ns=0;i=2275 */ +/* DeleteRawCapability - ns=0;i=11199 */ static UA_StatusCode function_namespace0_generated_139_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49874,26 +55516,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 859); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummary"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "DeleteRawCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 2274), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummary"), -UA_NODEID_NUMERIC(ns[0], 2150), +UA_NODEID_NUMERIC(ns[0], 11199LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "DeleteRawCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_139_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2275) +UA_NODEID_NUMERIC(ns[0], 11199LU) ); } -/* RejectedSessionCount - ns=0;i=3705 */ +/* UpdateDataCapability - ns=0;i=11198 */ static UA_StatusCode function_namespace0_generated_140_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49902,26 +55544,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "UpdateDataCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 3705), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11198LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "UpdateDataCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_140_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3705) +UA_NODEID_NUMERIC(ns[0], 11198LU) ); } -/* SessionTimeoutCount - ns=0;i=2281 */ +/* ReplaceDataCapability - ns=0;i=11197 */ static UA_StatusCode function_namespace0_generated_141_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49930,26 +55572,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceDataCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2281), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11197LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "ReplaceDataCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_141_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2281) +UA_NODEID_NUMERIC(ns[0], 11197LU) ); } -/* CumulatedSessionCount - ns=0;i=2278 */ +/* InsertDataCapability - ns=0;i=11196 */ static UA_StatusCode function_namespace0_generated_142_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49958,26 +55600,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "InsertDataCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2278), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11196LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "InsertDataCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_142_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2278) +UA_NODEID_NUMERIC(ns[0], 11196LU) ); } -/* PublishingIntervalCount - ns=0;i=2284 */ +/* AccessHistoryDataCapability - ns=0;i=11193 */ static UA_StatusCode function_namespace0_generated_143_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -49986,82 +55628,82 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU); +attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryDataCapability"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2284), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 11193LU), +UA_NODEID_NUMERIC(ns[0], 11192LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "AccessHistoryDataCapability"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_143_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2284) +UA_NODEID_NUMERIC(ns[0], 11193LU) ); } -/* SecurityRejectedRequestsCount - ns=0;i=2287 */ +/* ServiceLevel - ns=0;i=2267 */ static UA_StatusCode function_namespace0_generated_144_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 3LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ServiceLevel"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2287), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2267LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "ServiceLevel"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_144_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2287) +UA_NODEID_NUMERIC(ns[0], 2267LU) ); } -/* SessionAbortCount - ns=0;i=2282 */ +/* ServerStatus - ns=0;i=2256 */ static UA_StatusCode function_namespace0_generated_145_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 862LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatus"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2282), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ServerStatus"), +UA_NODEID_NUMERIC(ns[0], 2138LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_145_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2282) +UA_NODEID_NUMERIC(ns[0], 2256LU) ); } -/* RejectedRequestsCount - ns=0;i=2288 */ +/* ShutdownReason - ns=0;i=2993 */ static UA_StatusCode function_namespace0_generated_146_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -50070,26 +55712,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ShutdownReason"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2288), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2993LU), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ShutdownReason"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_146_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2288) +UA_NODEID_NUMERIC(ns[0], 2993LU) ); } -/* ServerViewCount - ns=0;i=2276 */ +/* SecondsTillShutdown - ns=0;i=2992 */ static UA_StatusCode function_namespace0_generated_147_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -50098,26 +55740,26 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +attr.displayName = UA_LOCALIZEDTEXT("", "SecondsTillShutdown"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2276), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerViewCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2992LU), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "SecondsTillShutdown"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_147_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2276) +UA_NODEID_NUMERIC(ns[0], 2992LU) ); } -/* CurrentSubscriptionCount - ns=0;i=2285 */ +/* BuildInfo - ns=0;i=2260 */ static UA_StatusCode function_namespace0_generated_148_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; @@ -50126,570 +55768,283 @@ attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 338LU); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2285), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "BuildInfo"), +UA_NODEID_NUMERIC(ns[0], 3051LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_148_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2285) +UA_NODEID_NUMERIC(ns[0], 2260LU) ); } -/* CurrentSessionCount - ns=0;i=2277 */ +/* BuildDate - ns=0;i=2266 */ static UA_StatusCode function_namespace0_generated_149_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildDate"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2277), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2266LU), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "BuildDate"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_149_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2277) +UA_NODEID_NUMERIC(ns[0], 2266LU) ); } -/* SecurityRejectedSessionCount - ns=0;i=2279 */ +/* BuildNumber - ns=0;i=2265 */ static UA_StatusCode function_namespace0_generated_150_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildNumber"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2279), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2265LU), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "BuildNumber"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_150_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2279) +UA_NODEID_NUMERIC(ns[0], 2265LU) ); } -/* CumulatedSubscriptionCount - ns=0;i=2286 */ +/* SoftwareVersion - ns=0;i=2264 */ static UA_StatusCode function_namespace0_generated_151_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareVersion"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2286), -UA_NODEID_NUMERIC(ns[0], 2275), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"), -UA_NODEID_NUMERIC(ns[0], 63), +UA_NODEID_NUMERIC(ns[0], 2264LU), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "SoftwareVersion"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_151_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2286) +UA_NODEID_NUMERIC(ns[0], 2264LU) ); } -/* EnabledFlag - ns=0;i=2294 */ +/* ManufacturerName - ns=0;i=2263 */ static UA_StatusCode function_namespace0_generated_152_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; -attr.accessLevel = 3; +attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ManufacturerName"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2294), -UA_NODEID_NUMERIC(ns[0], 2274), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "EnabledFlag"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2263LU), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ManufacturerName"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } static UA_StatusCode function_namespace0_generated_152_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2294) +UA_NODEID_NUMERIC(ns[0], 2263LU) ); } -/* ServerRedundancy - ns=0;i=2296 */ +/* ProductUri - ns=0;i=2262 */ static UA_StatusCode function_namespace0_generated_153_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancy"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2296), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerRedundancy"), -UA_NODEID_NUMERIC(ns[0], 2034), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_153_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2296) -); -} - -/* RedundancySupport - ns=0;i=3709 */ - -static UA_StatusCode function_namespace0_generated_154_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 851); -attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 3709), -UA_NODEID_NUMERIC(ns[0], 2296), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_154_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3709) -); -} - -/* ServerArray - ns=0;i=2254 */ - -static UA_StatusCode function_namespace0_generated_155_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -attr.valueRank = 1; -attr.arrayDimensionsSize = 1; -UA_UInt32 arrayDimensions[1]; -arrayDimensions[0] = 0; -attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerArray"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2254), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "ServerArray"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_155_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2254) -); -} - -/* ServerCapabilities - ns=0;i=2268 */ - -static UA_StatusCode function_namespace0_generated_156_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilities"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 2253), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ServerCapabilities"), -UA_NODEID_NUMERIC(ns[0], 2013), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_156_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2268) -); -} - -/* MaxBrowseContinuationPoints - ns=0;i=2735 */ - -static UA_StatusCode function_namespace0_generated_157_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 5); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxBrowseContinuationPoints"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2735), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxBrowseContinuationPoints"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_157_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2735) -); -} - -/* ModellingRules - ns=0;i=2996 */ - -static UA_StatusCode function_namespace0_generated_158_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRules"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2996), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "ModellingRules"), -UA_NODEID_NUMERIC(ns[0], 61), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_158_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2996) -); -} - -/* OperationLimits - ns=0;i=11704 */ - -static UA_StatusCode function_namespace0_generated_159_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "OperationLimits"), -UA_NODEID_NUMERIC(ns[0], 11564), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_159_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11704) -); -} - -/* MaxNodesPerNodeManagement - ns=0;i=11713 */ - -static UA_StatusCode function_namespace0_generated_160_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11713), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_160_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11713) -); -} - -/* MaxNodesPerWrite - ns=0;i=11707 */ - -static UA_StatusCode function_namespace0_generated_161_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11707), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_161_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11707) -); -} - -/* MaxNodesPerRead - ns=0;i=11705 */ - -static UA_StatusCode function_namespace0_generated_162_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11705), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_162_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11705) -); -} - -/* MaxNodesPerBrowse - ns=0;i=11710 */ - -static UA_StatusCode function_namespace0_generated_163_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11710), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_163_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11710) -); -} - -/* MaxMonitoredItemsPerCall - ns=0;i=11714 */ - -static UA_StatusCode function_namespace0_generated_164_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ProductUri"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11714), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2262LU), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ProductUri"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_164_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_153_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11714) +UA_NODEID_NUMERIC(ns[0], 2262LU) ); } -/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11712 */ +/* ProductName - ns=0;i=2261 */ -static UA_StatusCode function_namespace0_generated_165_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_154_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ProductName"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11712), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2261LU), +UA_NODEID_NUMERIC(ns[0], 2260LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "ProductName"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_165_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_154_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11712) +UA_NODEID_NUMERIC(ns[0], 2261LU) ); } -/* MaxNodesPerRegisterNodes - ns=0;i=11711 */ +/* State - ns=0;i=2259 */ -static UA_StatusCode function_namespace0_generated_166_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_155_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 852LU); +attr.displayName = UA_LOCALIZEDTEXT("", "State"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11711), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2259LU), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "State"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_166_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_155_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11711) +UA_NODEID_NUMERIC(ns[0], 2259LU) ); } -/* MaxNodesPerMethodCall - ns=0;i=11709 */ +/* CurrentTime - ns=0;i=2258 */ -static UA_StatusCode function_namespace0_generated_167_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_156_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU); +attr.displayName = UA_LOCALIZEDTEXT("", "CurrentTime"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11709), -UA_NODEID_NUMERIC(ns[0], 11704), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2258LU), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "CurrentTime"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_167_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_156_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11709) +UA_NODEID_NUMERIC(ns[0], 2258LU) ); } -/* MaxHistoryContinuationPoints - ns=0;i=2737 */ +/* StartTime - ns=0;i=2257 */ -static UA_StatusCode function_namespace0_generated_168_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_157_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 5); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxHistoryContinuationPoints"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU); +attr.displayName = UA_LOCALIZEDTEXT("", "StartTime"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2737), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxHistoryContinuationPoints"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2257LU), +UA_NODEID_NUMERIC(ns[0], 2256LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "StartTime"), +UA_NODEID_NUMERIC(ns[0], 63LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_168_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_157_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2737) +UA_NODEID_NUMERIC(ns[0], 2257LU) ); } -/* SoftwareCertificates - ns=0;i=3704 */ +/* NamespaceArray - ns=0;i=2255 */ -static UA_StatusCode function_namespace0_generated_169_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_158_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; attr.valueRank = 1; @@ -50697,30 +56052,30 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 344); -attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareCertificates"); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceArray"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 3704), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "SoftwareCertificates"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2255LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "NamespaceArray"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_169_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_158_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3704) +UA_NODEID_NUMERIC(ns[0], 2255LU) ); } -/* LocaleIdArray - ns=0;i=2271 */ +/* ServerArray - ns=0;i=2254 */ -static UA_StatusCode function_namespace0_generated_170_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_159_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; +attr.minimumSamplingInterval = 1000.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; attr.valueRank = 1; @@ -50728,77 +56083,60 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 295); -attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIdArray"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2271), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "LocaleIdArray"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_170_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2271) -); -} - -/* MaxQueryContinuationPoints - ns=0;i=2736 */ - -static UA_StatusCode function_namespace0_generated_171_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 5); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxQueryContinuationPoints"); +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerArray"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2736), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxQueryContinuationPoints"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 2254LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "ServerArray"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_171_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_159_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2736) +UA_NODEID_NUMERIC(ns[0], 2254LU) ); } -/* AggregateFunctions - ns=0;i=2997 */ +/* GetMonitoredItems - ns=0;i=11492 */ -static UA_StatusCode function_namespace0_generated_172_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_160_begin(UA_Server *server, UA_UInt16* ns) { +#ifdef UA_ENABLE_METHODCALLS UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2997), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"), -UA_NODEID_NUMERIC(ns[0], 61), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +UA_MethodAttributes attr = UA_MethodAttributes_default; +attr.executable = true; +attr.userExecutable = true; +attr.displayName = UA_LOCALIZEDTEXT("", "GetMonitoredItems"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD, +UA_NODEID_NUMERIC(ns[0], 11492LU), +UA_NODEID_NUMERIC(ns[0], 2253LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "GetMonitoredItems"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL); return retVal; +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ } -static UA_StatusCode function_namespace0_generated_172_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2997) -); +static UA_StatusCode function_namespace0_generated_160_finish(UA_Server *server, UA_UInt16* ns) { +#ifdef UA_ENABLE_METHODCALLS +return UA_Server_addMethodNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11492LU) +, NULL, 0, NULL, 0, NULL); +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ } -/* ServerProfileArray - ns=0;i=2269 */ +/* OutputArguments - ns=0;i=11494 */ -static UA_StatusCode function_namespace0_generated_173_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_161_begin(UA_Server *server, UA_UInt16* ns) { +#ifdef UA_ENABLE_METHODCALLS UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; @@ -50809,952 +56147,726 @@ attr.arrayDimensionsSize = 1; UA_UInt32 arrayDimensions[1]; arrayDimensions[0] = 0; attr.arrayDimensions = &arrayDimensions[0]; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "ServerProfileArray"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2269), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "ServerProfileArray"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_173_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2269) -); -} - -/* HistoryServerCapabilities - ns=0;i=11192 */ - -static UA_StatusCode function_namespace0_generated_174_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilities"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "HistoryServerCapabilities"), -UA_NODEID_NUMERIC(ns[0], 2330), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_174_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11192) -); -} - -/* MaxReturnDataValues - ns=0;i=11273 */ - -static UA_StatusCode function_namespace0_generated_175_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnDataValues"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11273), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxReturnDataValues"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_175_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11273) -); -} - -/* InsertAnnotationCapability - ns=0;i=11275 */ - -static UA_StatusCode function_namespace0_generated_176_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "InsertAnnotationCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11275), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "InsertAnnotationCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_176_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11275) -); -} - -/* AggregateFunctions - ns=0;i=11201 */ - -static UA_StatusCode function_namespace0_generated_177_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 11201), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"), -UA_NODEID_NUMERIC(ns[0], 61), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_177_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11201) -); -} +attr.dataType = UA_NODEID_NUMERIC(ns[0], 296LU); +UA_Argument variablenode_ns_0_i_11494_variant_DataContents[2]; -/* ReplaceDataCapability - ns=0;i=11197 */ +UA_init(&variablenode_ns_0_i_11494_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]); +variablenode_ns_0_i_11494_variant_DataContents[0].name = UA_STRING("ServerHandles"); +variablenode_ns_0_i_11494_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +variablenode_ns_0_i_11494_variant_DataContents[0].valueRank = (UA_Int32) 1; +UA_STACKARRAY(UA_UInt32, variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions, 1); +UA_init(variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]); +variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions[0] = (UA_UInt32) 0; +variablenode_ns_0_i_11494_variant_DataContents[0].arrayDimensionsSize = 1; +variablenode_ns_0_i_11494_variant_DataContents[0].arrayDimensions = variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions; -static UA_StatusCode function_namespace0_generated_178_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceDataCapability"); +UA_init(&variablenode_ns_0_i_11494_variant_DataContents[1], &UA_TYPES[UA_TYPES_ARGUMENT]); +variablenode_ns_0_i_11494_variant_DataContents[1].name = UA_STRING("ClientHandles"); +variablenode_ns_0_i_11494_variant_DataContents[1].dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +variablenode_ns_0_i_11494_variant_DataContents[1].valueRank = (UA_Int32) 1; +UA_STACKARRAY(UA_UInt32, variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions, 1); +UA_init(variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]); +variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions[0] = (UA_UInt32) 0; +variablenode_ns_0_i_11494_variant_DataContents[1].arrayDimensionsSize = 1; +variablenode_ns_0_i_11494_variant_DataContents[1].arrayDimensions = variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions; +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11494_variant_DataContents, (UA_Int32) 2, &UA_TYPES[UA_TYPES_ARGUMENT]); +attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11197), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "ReplaceDataCapability"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 11494LU), +UA_NODEID_NUMERIC(ns[0], 11492LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "OutputArguments"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_178_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11197) -); -} -/* DeleteRawCapability - ns=0;i=11199 */ -static UA_StatusCode function_namespace0_generated_179_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "DeleteRawCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11199), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "DeleteRawCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ } -static UA_StatusCode function_namespace0_generated_179_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_161_finish(UA_Server *server, UA_UInt16* ns) { +#ifdef UA_ENABLE_METHODCALLS return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11199) +UA_NODEID_NUMERIC(ns[0], 11494LU) ); +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ } -/* UpdateDataCapability - ns=0;i=11198 */ +/* InputArguments - ns=0;i=11493 */ -static UA_StatusCode function_namespace0_generated_180_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_162_begin(UA_Server *server, UA_UInt16* ns) { +#ifdef UA_ENABLE_METHODCALLS UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "UpdateDataCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11198), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "UpdateDataCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_180_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11198) -); -} - -/* InsertDataCapability - ns=0;i=11196 */ +attr.valueRank = 1; +attr.arrayDimensionsSize = 1; +UA_UInt32 arrayDimensions[1]; +arrayDimensions[0] = 0; +attr.arrayDimensions = &arrayDimensions[0]; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 296LU); +UA_Argument variablenode_ns_0_i_11493_variant_DataContents[1]; -static UA_StatusCode function_namespace0_generated_181_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "InsertDataCapability"); +UA_init(&variablenode_ns_0_i_11493_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]); +variablenode_ns_0_i_11493_variant_DataContents[0].name = UA_STRING("SubscriptionId"); +variablenode_ns_0_i_11493_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7LU); +variablenode_ns_0_i_11493_variant_DataContents[0].valueRank = (UA_Int32) -1; +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11493_variant_DataContents, (UA_Int32) 1, &UA_TYPES[UA_TYPES_ARGUMENT]); +attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11196), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "InsertDataCapability"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 11493LU), +UA_NODEID_NUMERIC(ns[0], 11492LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "InputArguments"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_181_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11196) -); -} - -/* ReplaceEventCapability - ns=0;i=11282 */ -static UA_StatusCode function_namespace0_generated_182_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceEventCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11282), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "ReplaceEventCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); return retVal; +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ } -static UA_StatusCode function_namespace0_generated_182_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_162_finish(UA_Server *server, UA_UInt16* ns) { +#ifdef UA_ENABLE_METHODCALLS return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11282) +UA_NODEID_NUMERIC(ns[0], 11493LU) ); +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ } -/* AccessHistoryEventsCapability - ns=0;i=11242 */ +/* VendorServerInfo - ns=0;i=2011 */ -static UA_StatusCode function_namespace0_generated_183_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_163_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryEventsCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11242), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "AccessHistoryEventsCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2011LU), +UA_NODEID_NUMERIC(ns[0], 2004LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"), +UA_NODEID_NUMERIC(ns[0], 2033LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_183_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_163_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11242) +UA_NODEID_NUMERIC(ns[0], 2011LU) ); } -/* MaxReturnEventValues - ns=0;i=11274 */ +/* ModellingRuleType - ns=0;i=77 */ -static UA_StatusCode function_namespace0_generated_184_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_164_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); -attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnEventValues"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11274), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MaxReturnEventValues"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRuleType"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 77LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), +UA_QUALIFIEDNAME(ns[0], "ModellingRuleType"), + UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_184_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_164_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11274) +UA_NODEID_NUMERIC(ns[0], 77LU) ); } -/* AccessHistoryDataCapability - ns=0;i=11193 */ +/* ExposesItsArray - ns=0;i=83 */ -static UA_StatusCode function_namespace0_generated_185_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_165_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryDataCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11193), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "AccessHistoryDataCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ExposesItsArray"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 83LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "ExposesItsArray"), +UA_NODEID_NUMERIC(ns[0], 77LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_185_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_165_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11193) +UA_NODEID_NUMERIC(ns[0], 83LU) ); } -/* DeleteEventCapability - ns=0;i=11502 */ +/* NamingRule - ns=0;i=114 */ -static UA_StatusCode function_namespace0_generated_186_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_166_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "DeleteEventCapability"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU); +UA_Int32 *variablenode_ns_0_i_114_variant_DataContents = UA_Int32_new(); +if (!variablenode_ns_0_i_114_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_Int32_init(variablenode_ns_0_i_114_variant_DataContents); +*variablenode_ns_0_i_114_variant_DataContents = (UA_Int32) 3; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_114_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11502), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "DeleteEventCapability"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 114LU), +UA_NODEID_NUMERIC(ns[0], 83LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "NamingRule"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Int32_delete(variablenode_ns_0_i_114_variant_DataContents); return retVal; } -static UA_StatusCode function_namespace0_generated_186_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_166_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11502) +UA_NODEID_NUMERIC(ns[0], 114LU) ); } -/* InsertEventCapability - ns=0;i=11281 */ +/* Optional - ns=0;i=80 */ -static UA_StatusCode function_namespace0_generated_187_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_167_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "InsertEventCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11281), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "InsertEventCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "Optional"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 80LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "Optional"), +UA_NODEID_NUMERIC(ns[0], 77LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11570LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11574LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11573LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11551LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11572LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11569LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2366LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2371LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11571LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11567LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11565LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2367LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3190LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2370LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_187_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_167_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11281) +UA_NODEID_NUMERIC(ns[0], 80LU) ); } -/* DeleteAtTimeCapability - ns=0;i=11200 */ +/* NamingRule - ns=0;i=113 */ -static UA_StatusCode function_namespace0_generated_188_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_168_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "DeleteAtTimeCapability"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU); +UA_Int32 *variablenode_ns_0_i_113_variant_DataContents = UA_Int32_new(); +if (!variablenode_ns_0_i_113_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_Int32_init(variablenode_ns_0_i_113_variant_DataContents); +*variablenode_ns_0_i_113_variant_DataContents = (UA_Int32) 2; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_113_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11200), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "DeleteAtTimeCapability"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 113LU), +UA_NODEID_NUMERIC(ns[0], 80LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "NamingRule"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Int32_delete(variablenode_ns_0_i_113_variant_DataContents); return retVal; } -static UA_StatusCode function_namespace0_generated_188_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_168_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11200) +UA_NODEID_NUMERIC(ns[0], 113LU) ); } -/* UpdateEventCapability - ns=0;i=11283 */ +/* Mandatory - ns=0;i=78 */ -static UA_StatusCode function_namespace0_generated_189_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_169_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_VariableAttributes attr = UA_VariableAttributes_default; -attr.minimumSamplingInterval = 0.000000; -attr.userAccessLevel = 1; -attr.accessLevel = 1; -/* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); -attr.displayName = UA_LOCALIZEDTEXT("", "UpdateEventCapability"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 11283), -UA_NODEID_NUMERIC(ns[0], 11192), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "UpdateEventCapability"), -UA_NODEID_NUMERIC(ns[0], 68), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "Mandatory"); +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 78LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "Mandatory"), +UA_NODEID_NUMERIC(ns[0], 77LU), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2374LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2369LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2050LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12169LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7611LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2042LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2046LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2375LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12078LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2035LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2051LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2045LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11241LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2011LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2377LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2047LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11461LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2044LU), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2043LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_189_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_169_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 11283) +UA_NODEID_NUMERIC(ns[0], 78LU) ); } -/* MinSupportedSampleRate - ns=0;i=2272 */ +/* NamingRule - ns=0;i=112 */ -static UA_StatusCode function_namespace0_generated_190_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_170_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 290); -attr.displayName = UA_LOCALIZEDTEXT("", "MinSupportedSampleRate"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU); +UA_Int32 *variablenode_ns_0_i_112_variant_DataContents = UA_Int32_new(); +if (!variablenode_ns_0_i_112_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_Int32_init(variablenode_ns_0_i_112_variant_DataContents); +*variablenode_ns_0_i_112_variant_DataContents = (UA_Int32) 1; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_112_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 2272), -UA_NODEID_NUMERIC(ns[0], 2268), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "MinSupportedSampleRate"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 112LU), +UA_NODEID_NUMERIC(ns[0], 78LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "NamingRule"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Int32_delete(variablenode_ns_0_i_112_variant_DataContents); return retVal; } -static UA_StatusCode function_namespace0_generated_190_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_170_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2272) +UA_NODEID_NUMERIC(ns[0], 112LU) ); } -/* VendorServerInfo - ns=0;i=2011 */ +/* MandatoryPlaceholder - ns=0;i=11510 */ -static UA_StatusCode function_namespace0_generated_191_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_171_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo"); +attr.displayName = UA_LOCALIZEDTEXT("", "MandatoryPlaceholder"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 2011), -UA_NODEID_NUMERIC(ns[0], 2004), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"), -UA_NODEID_NUMERIC(ns[0], 2033), +UA_NODEID_NUMERIC(ns[0], 11510LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "MandatoryPlaceholder"), +UA_NODEID_NUMERIC(ns[0], 77LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_191_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 2011) -); -} - -/* ModellingRuleType - ns=0;i=77 */ - -static UA_StatusCode function_namespace0_generated_192_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRuleType"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 77), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), -UA_QUALIFIEDNAME(ns[0], "ModellingRuleType"), - UA_NODEID_NULL, -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_192_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_171_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 77) +UA_NODEID_NUMERIC(ns[0], 11510LU) ); } -/* NamingRule - ns=0;i=111 */ +/* NamingRule - ns=0;i=11511 */ -static UA_StatusCode function_namespace0_generated_193_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_172_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 120); -UA_Int32 *variablenode_ns_0_i_111_variant_DataContents = UA_Int32_new(); -if (!variablenode_ns_0_i_111_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; -UA_Int32_init(variablenode_ns_0_i_111_variant_DataContents); -*variablenode_ns_0_i_111_variant_DataContents = (UA_Int32) 1; -UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_111_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU); +UA_Int32 *variablenode_ns_0_i_11511_variant_DataContents = UA_Int32_new(); +if (!variablenode_ns_0_i_11511_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_Int32_init(variablenode_ns_0_i_11511_variant_DataContents); +*variablenode_ns_0_i_11511_variant_DataContents = (UA_Int32) 1; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_11511_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 111), -UA_NODEID_NUMERIC(ns[0], 77), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 11511LU), +UA_NODEID_NUMERIC(ns[0], 11510LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "NamingRule"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -UA_Int32_delete(variablenode_ns_0_i_111_variant_DataContents); +UA_Int32_delete(variablenode_ns_0_i_11511_variant_DataContents); return retVal; } -static UA_StatusCode function_namespace0_generated_193_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_172_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 111) +UA_NODEID_NUMERIC(ns[0], 11511LU) ); } -/* Optional - ns=0;i=80 */ +/* OptionalPlaceholder - ns=0;i=11508 */ -static UA_StatusCode function_namespace0_generated_194_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_173_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Optional"); +attr.displayName = UA_LOCALIZEDTEXT("", "OptionalPlaceholder"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 80), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), -UA_QUALIFIEDNAME(ns[0], "Optional"), -UA_NODEID_NUMERIC(ns[0], 77), +UA_NODEID_NUMERIC(ns[0], 11508LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "OptionalPlaceholder"), +UA_NODEID_NUMERIC(ns[0], 77LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11571), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11574), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2366), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2371), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2370), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11569), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3190), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11565), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11567), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11570), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11573), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11551), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11572), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2367), false); return retVal; } -static UA_StatusCode function_namespace0_generated_194_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_173_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 80) +UA_NODEID_NUMERIC(ns[0], 11508LU) ); } -/* NamingRule - ns=0;i=113 */ +/* NamingRule - ns=0;i=11509 */ -static UA_StatusCode function_namespace0_generated_195_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_174_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 120); -UA_Int32 *variablenode_ns_0_i_113_variant_DataContents = UA_Int32_new(); -if (!variablenode_ns_0_i_113_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; -UA_Int32_init(variablenode_ns_0_i_113_variant_DataContents); -*variablenode_ns_0_i_113_variant_DataContents = (UA_Int32) 2; -UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_113_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU); +UA_Int32 *variablenode_ns_0_i_11509_variant_DataContents = UA_Int32_new(); +if (!variablenode_ns_0_i_11509_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_Int32_init(variablenode_ns_0_i_11509_variant_DataContents); +*variablenode_ns_0_i_11509_variant_DataContents = (UA_Int32) 2; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_11509_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 113), -UA_NODEID_NUMERIC(ns[0], 80), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 11509LU), +UA_NODEID_NUMERIC(ns[0], 11508LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "NamingRule"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -UA_Int32_delete(variablenode_ns_0_i_113_variant_DataContents); +UA_Int32_delete(variablenode_ns_0_i_11509_variant_DataContents); return retVal; } -static UA_StatusCode function_namespace0_generated_195_finish(UA_Server *server, UA_UInt16* ns) { -return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 113) -); -} - -/* Mandatory - ns=0;i=78 */ - -static UA_StatusCode function_namespace0_generated_196_begin(UA_Server *server, UA_UInt16* ns) { -UA_StatusCode retVal = UA_STATUSCODE_GOOD; -UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Mandatory"); -retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 78), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), -UA_QUALIFIEDNAME(ns[0], "Mandatory"), -UA_NODEID_NUMERIC(ns[0], 77), -(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2152), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2011), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2151), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2051), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2157), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2047), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2045), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 111), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2043), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2035), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2160), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11241), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2159), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2162), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2154), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11461), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2155), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12169), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2163), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2369), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7611), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2046), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2374), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2377), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2044), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2050), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2375), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2153), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2161), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2156), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2042), false); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12078), false); -return retVal; -} - -static UA_StatusCode function_namespace0_generated_196_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_174_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 78) +UA_NODEID_NUMERIC(ns[0], 11509LU) ); } -/* NamingRule - ns=0;i=112 */ +/* NamingRule - ns=0;i=111 */ -static UA_StatusCode function_namespace0_generated_197_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_175_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 120); -UA_Int32 *variablenode_ns_0_i_112_variant_DataContents = UA_Int32_new(); -if (!variablenode_ns_0_i_112_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; -UA_Int32_init(variablenode_ns_0_i_112_variant_DataContents); -*variablenode_ns_0_i_112_variant_DataContents = (UA_Int32) 1; -UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_112_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU); +UA_Int32 *variablenode_ns_0_i_111_variant_DataContents = UA_Int32_new(); +if (!variablenode_ns_0_i_111_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_Int32_init(variablenode_ns_0_i_111_variant_DataContents); +*variablenode_ns_0_i_111_variant_DataContents = (UA_Int32) 1; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_111_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]); attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 112), -UA_NODEID_NUMERIC(ns[0], 78), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 111LU), +UA_NODEID_NUMERIC(ns[0], 77LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "NamingRule"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -UA_Int32_delete(variablenode_ns_0_i_112_variant_DataContents); +UA_Int32_delete(variablenode_ns_0_i_111_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 111LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 78LU), true); return retVal; } -static UA_StatusCode function_namespace0_generated_197_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_175_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 112) +UA_NODEID_NUMERIC(ns[0], 111LU) ); } /* DataTypeEncodingType - ns=0;i=76 */ -static UA_StatusCode function_namespace0_generated_198_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_176_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeEncodingType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 76), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 76LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DataTypeEncodingType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_198_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_176_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 76) +UA_NODEID_NUMERIC(ns[0], 76LU) ); } -/* Default JSON - ns=0;i=15375 */ +/* Default Binary - ns=0;i=8251 */ -static UA_StatusCode function_namespace0_generated_199_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_177_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON"); +attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 15375), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), -UA_QUALIFIEDNAME(ns[0], "Default JSON"), -UA_NODEID_NUMERIC(ns[0], 76), +UA_NODEID_NUMERIC(ns[0], 8251LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "Default Binary"), +UA_NODEID_NUMERIC(ns[0], 76LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 15375), UA_NODEID_NUMERIC(ns[0], 38), UA_EXPANDEDNODEID_NUMERIC(ns[0], 884), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 8251LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7594LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_199_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_177_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 15375) +UA_NODEID_NUMERIC(ns[0], 8251LU) ); } -/* Default Binary - ns=0;i=8251 */ +/* Default Binary - ns=0;i=298 */ -static UA_StatusCode function_namespace0_generated_200_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_178_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 8251), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 298LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), UA_QUALIFIEDNAME(ns[0], "Default Binary"), -UA_NODEID_NUMERIC(ns[0], 76), +UA_NODEID_NUMERIC(ns[0], 76LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 8251), UA_NODEID_NUMERIC(ns[0], 38), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7594), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 298LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 296LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_200_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_178_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 8251) +UA_NODEID_NUMERIC(ns[0], 298LU) ); } -/* Default Binary - ns=0;i=298 */ +/* Default JSON - ns=0;i=15376 */ -static UA_StatusCode function_namespace0_generated_201_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_179_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary"); +attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 298), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), -UA_QUALIFIEDNAME(ns[0], "Default Binary"), -UA_NODEID_NUMERIC(ns[0], 76), +UA_NODEID_NUMERIC(ns[0], 15376LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_QUALIFIEDNAME(ns[0], "Default JSON"), +UA_NODEID_NUMERIC(ns[0], 76LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 298), UA_NODEID_NUMERIC(ns[0], 38), UA_EXPANDEDNODEID_NUMERIC(ns[0], 296), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 15376LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 887LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_201_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_179_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 298) +UA_NODEID_NUMERIC(ns[0], 15376LU) ); } -/* Default JSON - ns=0;i=15376 */ +/* Default JSON - ns=0;i=15375 */ -static UA_StatusCode function_namespace0_generated_202_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_180_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 15376), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 15375LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), UA_QUALIFIEDNAME(ns[0], "Default JSON"), -UA_NODEID_NUMERIC(ns[0], 76), +UA_NODEID_NUMERIC(ns[0], 76LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 15376), UA_NODEID_NUMERIC(ns[0], 38), UA_EXPANDEDNODEID_NUMERIC(ns[0], 887), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 15375LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 884LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_202_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_180_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 15376) +UA_NODEID_NUMERIC(ns[0], 15375LU) ); } /* DataTypeSystemType - ns=0;i=75 */ -static UA_StatusCode function_namespace0_generated_203_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_181_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeSystemType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, -UA_NODEID_NUMERIC(ns[0], 75), -UA_NODEID_NUMERIC(ns[0], 58), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 75LU), +UA_NODEID_NUMERIC(ns[0], 58LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DataTypeSystemType"), UA_NODEID_NULL, (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_203_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_181_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 75) +UA_NODEID_NUMERIC(ns[0], 75LU) ); } -/* XML Schema - ns=0;i=92 */ +/* OPC Binary - ns=0;i=93 */ -static UA_StatusCode function_namespace0_generated_204_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_182_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "XML Schema"); +attr.displayName = UA_LOCALIZEDTEXT("", "OPC Binary"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 92), -UA_NODEID_NUMERIC(ns[0], 90), -UA_NODEID_NUMERIC(ns[0], 35), -UA_QUALIFIEDNAME(ns[0], "XML Schema"), -UA_NODEID_NUMERIC(ns[0], 75), +UA_NODEID_NUMERIC(ns[0], 93LU), +UA_NODEID_NUMERIC(ns[0], 90LU), +UA_NODEID_NUMERIC(ns[0], 35LU), +UA_QUALIFIEDNAME(ns[0], "OPC Binary"), +UA_NODEID_NUMERIC(ns[0], 75LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_204_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_182_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 92) +UA_NODEID_NUMERIC(ns[0], 93LU) ); } -/* OPC Binary - ns=0;i=93 */ +/* XML Schema - ns=0;i=92 */ -static UA_StatusCode function_namespace0_generated_205_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_183_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; -attr.displayName = UA_LOCALIZEDTEXT("", "OPC Binary"); +attr.displayName = UA_LOCALIZEDTEXT("", "XML Schema"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 93), -UA_NODEID_NUMERIC(ns[0], 90), -UA_NODEID_NUMERIC(ns[0], 35), -UA_QUALIFIEDNAME(ns[0], "OPC Binary"), -UA_NODEID_NUMERIC(ns[0], 75), +UA_NODEID_NUMERIC(ns[0], 92LU), +UA_NODEID_NUMERIC(ns[0], 90LU), +UA_NODEID_NUMERIC(ns[0], 35LU), +UA_QUALIFIEDNAME(ns[0], "XML Schema"), +UA_NODEID_NUMERIC(ns[0], 75LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_205_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_183_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 93) +UA_NODEID_NUMERIC(ns[0], 92LU) ); } /* DataTypeDictionaryType - ns=0;i=72 */ -static UA_StatusCode function_namespace0_generated_206_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_184_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 15); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU); attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDictionaryType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 72), -UA_NODEID_NUMERIC(ns[0], 63), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 72LU), +UA_NODEID_NUMERIC(ns[0], 63LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DataTypeDictionaryType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_206_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_184_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 72) +UA_NODEID_NUMERIC(ns[0], 72LU) ); } /* Opc.Ua - ns=0;i=7617 */ +static const UA_Byte variablenode_ns_0_i_7617_variant_DataContents_byteArray[177218] = {60, 111, 112, 99, 58, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 111, 112, 99, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 66, 105, 110, 97, 114, 121, 83, 99, 104, 101, 109, 97, 47, 34, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 120, 115, 105, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 88, 77, 76, 83, 99, 104, 101, 109, 97, 45, 105, 110, 115, 116, 97, 110, 99, 101, 34, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 117, 97, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 85, 65, 47, 34, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 116, 110, 115, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 85, 65, 47, 34, 13, 10, 32, 32, 68, 101, 102, 97, 117, 108, 116, 66, 121, 116, 101, 79, 114, 100, 101, 114, 61, 34, 76, 105, 116, 116, 108, 101, 69, 110, 100, 105, 97, 110, 34, 13, 10, 32, 32, 84, 97, 114, 103, 101, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 85, 65, 47, 34, 13, 10, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 73, 109, 112, 111, 114, 116, 32, 78, 97, 109, 101, 115, 112, 97, 99, 101, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 66, 105, 110, 97, 114, 121, 83, 99, 104, 101, 109, 97, 47, 34, 32, 47, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 88, 109, 108, 69, 108, 101, 109, 101, 110, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 110, 32, 88, 77, 76, 32, 101, 108, 101, 109, 101, 110, 116, 32, 101, 110, 99, 111, 100, 101, 100, 32, 97, 115, 32, 97, 32, 85, 84, 70, 45, 56, 32, 115, 116, 114, 105, 110, 103, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 76, 101, 110, 103, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 54, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 84, 104, 101, 32, 112, 111, 115, 115, 105, 98, 108, 101, 32, 101, 110, 99, 111, 100, 105, 110, 103, 115, 32, 102, 111, 114, 32, 97, 32, 78, 111, 100, 101, 73, 100, 32, 118, 97, 108, 117, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 110, 32, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 32, 102, 111, 114, 32, 97, 32, 110, 111, 100, 101, 32, 105, 110, 32, 97, 32, 85, 65, 32, 115, 101, 114, 118, 101, 114, 32, 97, 100, 100, 114, 101, 115, 115, 32, 115, 112, 97, 99, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 84, 119, 111, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 70, 111, 117, 114, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 117, 109, 101, 114, 105, 99, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 71, 117, 105, 100, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 110, 32, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 32, 102, 111, 114, 32, 97, 32, 110, 111, 100, 101, 32, 105, 110, 32, 97, 32, 85, 65, 32, 115, 101, 114, 118, 101, 114, 32, 97, 100, 100, 114, 101, 115, 115, 32, 115, 112, 97, 99, 101, 32, 113, 117, 97, 108, 105, 102, 105, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 99, 111, 109, 112, 108, 101, 116, 101, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 32, 115, 116, 114, 105, 110, 103, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 73, 110, 100, 101, 120, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 84, 119, 111, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 70, 111, 117, 114, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 117, 109, 101, 114, 105, 99, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 71, 117, 105, 100, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 101, 114, 118, 101, 114, 73, 110, 100, 101, 120, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 66, 121, 116, 101, 79, 114, 100, 101, 114, 83, 105, 103, 110, 105, 102, 105, 99, 97, 110, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 51, 50, 45, 98, 105, 116, 32, 115, 116, 97, 116, 117, 115, 32, 99, 111, 100, 101, 32, 118, 97, 108, 117, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 114, 101, 99, 117, 114, 115, 105, 118, 101, 32, 115, 116, 114, 117, 99, 116, 117, 114, 101, 32, 99, 111, 110, 116, 97, 105, 110, 105, 110, 103, 32, 100, 105, 97, 103, 110, 111, 115, 116, 105, 99, 32, 105, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 32, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 115, 116, 97, 116, 117, 115, 32, 99, 111, 100, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 98, 111, 108, 105, 99, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 98, 111, 108, 105, 99, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 121, 109, 98, 111, 108, 105, 99, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 73, 110, 110, 101, 114, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 73, 110, 110, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 115, 116, 114, 105, 110, 103, 32, 113, 117, 97, 108, 105, 102, 105, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 32, 105, 110, 100, 101, 120, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 115, 116, 114, 105, 110, 103, 32, 113, 117, 97, 108, 105, 102, 105, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 32, 105, 110, 100, 101, 120, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 101, 120, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 118, 97, 108, 117, 101, 32, 119, 105, 116, 104, 32, 97, 110, 32, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 44, 32, 97, 110, 100, 32, 113, 117, 97, 108, 105, 116, 121, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 108, 117, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 115, 101, 114, 105, 97, 108, 105, 122, 101, 100, 32, 111, 98, 106, 101, 99, 116, 32, 112, 114, 101, 102, 105, 120, 101, 100, 32, 119, 105, 116, 104, 32, 105, 116, 115, 32, 100, 97, 116, 97, 32, 116, 121, 112, 101, 32, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 105, 110, 97, 114, 121, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 109, 108, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 84, 121, 112, 101, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 100, 121, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 66, 111, 100, 121, 76, 101, 110, 103, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 110, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 117, 110, 105, 111, 110, 32, 111, 102, 32, 115, 101, 118, 101, 114, 97, 108, 32, 116, 121, 112, 101, 115, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 49, 34, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 49, 34, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 111, 108, 101, 97, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 66, 121, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 49, 54, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 73, 110, 116, 49, 54, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 51, 50, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 73, 110, 116, 51, 50, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 55, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 54, 52, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 54, 52, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 73, 110, 116, 54, 52, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 54, 52, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 57, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 108, 111, 97, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 111, 117, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 109, 108, 69, 108, 101, 109, 101, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 88, 109, 108, 69, 108, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 55, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 57, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 105, 110, 103, 82, 117, 108, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 97, 110, 100, 97, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 116, 105, 111, 110, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 115, 116, 114, 97, 105, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 32, 32, 32, 32, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 66, 77, 80, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 71, 73, 70, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 74, 80, 71, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 80, 78, 71, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 117, 100, 105, 111, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 105, 116, 70, 105, 101, 108, 100, 77, 97, 115, 107, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 112, 104, 101, 109, 101, 114, 97, 108, 75, 101, 121, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 99, 75, 101, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 97, 116, 105, 111, 110, 97, 108, 78, 117, 109, 98, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 97, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 110, 111, 109, 105, 110, 97, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 101, 99, 116, 111, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 86, 101, 99, 116, 111, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 86, 101, 99, 116, 111, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 89, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 90, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 89, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 90, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 114, 97, 109, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 70, 114, 97, 109, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 114, 97, 109, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 104, 114, 101, 101, 68, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 104, 114, 101, 101, 68, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 110, 70, 105, 108, 101, 77, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 114, 97, 115, 101, 69, 120, 105, 115, 116, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 101, 110, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 116, 121, 67, 114, 105, 116, 101, 114, 105, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 117, 109, 98, 112, 114, 105, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 111, 110, 121, 109, 111, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 100, 85, 115, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 116, 121, 77, 97, 112, 112, 105, 110, 103, 82, 117, 108, 101, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 105, 116, 101, 114, 105, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 73, 100, 101, 110, 116, 105, 116, 121, 67, 114, 105, 116, 101, 114, 105, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 105, 116, 101, 114, 105, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 99, 121, 85, 110, 105, 116, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 112, 111, 110, 101, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 112, 104, 97, 98, 101, 116, 105, 99, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 99, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 76, 105, 115, 116, 77, 97, 115, 107, 115, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 76, 105, 115, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 76, 105, 115, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 99, 105, 109, 97, 108, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 99, 97, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 83, 99, 104, 101, 109, 97, 72, 101, 97, 100, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 116, 73, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 116, 73, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 65, 66, 105, 110, 97, 114, 121, 70, 105, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 83, 99, 104, 101, 109, 97, 72, 101, 97, 100, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 99, 104, 101, 109, 97, 76, 111, 99, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 108, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 108, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 83, 116, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 97, 117, 115, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 116, 105, 111, 110, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 114, 114, 111, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 83, 99, 104, 101, 109, 97, 72, 101, 97, 100, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 70, 105, 101, 108, 100, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 70, 108, 97, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 70, 108, 97, 103, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 116, 73, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 70, 108, 97, 103, 115, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 49, 54, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 109, 111, 116, 101, 100, 70, 105, 101, 108, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 106, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 70, 111, 108, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 111, 108, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 70, 111, 108, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 120, 116, 101, 110, 115, 105, 111, 110, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 116, 101, 110, 115, 105, 111, 110, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 120, 116, 101, 110, 115, 105, 111, 110, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 86, 97, 114, 105, 97, 98, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 86, 97, 114, 105, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 72, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 116, 105, 116, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 101, 116, 97, 68, 97, 116, 97, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 101, 116, 97, 68, 97, 116, 97, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 73, 116, 101, 109, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 86, 97, 114, 105, 97, 98, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 69, 118, 101, 110, 116, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 97, 119, 68, 97, 116, 97, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 70, 114, 97, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 101, 112, 65, 108, 105, 118, 101, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 101, 97, 100, 101, 114, 76, 97, 121, 111, 117, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 114, 101, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 73, 110, 116, 101, 114, 102, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 85, 114, 108, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 73, 110, 116, 101, 114, 102, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 82, 101, 99, 101, 105, 118, 101, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 70, 114, 97, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 101, 97, 100, 101, 114, 76, 97, 121, 111, 117, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 70, 105, 101, 108, 100, 84, 97, 114, 103, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 84, 97, 114, 103, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 101, 105, 118, 101, 114, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 72, 97, 110, 100, 108, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 72, 97, 110, 100, 108, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 72, 97, 110, 100, 108, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 85, 115, 97, 98, 108, 101, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 77, 105, 114, 114, 111, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 101, 110, 116, 78, 111, 100, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 114, 100, 101, 114, 105, 110, 103, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 100, 101, 102, 105, 110, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 115, 99, 101, 110, 100, 105, 110, 103, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 115, 99, 101, 110, 100, 105, 110, 103, 87, 114, 105, 116, 101, 114, 73, 100, 83, 105, 110, 103, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 97, 121, 108, 111, 97, 100, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 109, 111, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 114, 100, 101, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 79, 114, 100, 101, 114, 105, 110, 103, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 97, 106, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 101, 100, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 101, 105, 118, 101, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 110, 103, 108, 101, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 108, 121, 84, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 103, 114, 97, 109, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 65, 100, 100, 114, 101, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 103, 114, 97, 109, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 82, 101, 112, 101, 97, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 82, 101, 112, 101, 97, 116, 68, 101, 108, 97, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 101, 115, 116, 69, 102, 102, 111, 114, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 76, 101, 97, 115, 116, 79, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 77, 111, 115, 116, 79, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 97, 99, 116, 108, 121, 79, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 68, 101, 108, 105, 118, 101, 114, 121, 71, 117, 97, 114, 97, 110, 116, 101, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 68, 101, 108, 105, 118, 101, 114, 121, 71, 117, 97, 114, 97, 110, 116, 101, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 85, 112, 100, 97, 116, 101, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 68, 101, 108, 105, 118, 101, 114, 121, 71, 117, 97, 114, 97, 110, 116, 101, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 76, 101, 118, 101, 108, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 118, 97, 110, 99, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 102, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 98, 117, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 67, 111, 117, 110, 116, 101, 114, 67, 108, 97, 115, 115, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 114, 114, 111, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 105, 97, 115, 78, 97, 109, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 105, 97, 115, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 100, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 97, 113, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 115, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 101, 114, 116, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 101, 105, 118, 101, 69, 118, 101, 110, 116, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 48, 57, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 49, 57, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 51, 56, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 55, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 53, 53, 51, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 56, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 110, 116, 105, 99, 67, 104, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 69, 120, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 110, 116, 105, 99, 67, 104, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 97, 116, 111, 109, 105, 99, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 97, 116, 111, 109, 105, 99, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 70, 117, 108, 108, 65, 114, 114, 97, 121, 79, 110, 108, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 83, 117, 98, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 56, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 84, 111, 69, 118, 101, 110, 116, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 49, 54, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 105, 110, 103, 82, 101, 113, 117, 105, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 114, 121, 112, 116, 105, 111, 110, 82, 101, 113, 117, 105, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 105, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 121, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 87, 105, 116, 104, 79, 112, 116, 105, 111, 110, 97, 108, 70, 105, 101, 108, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 70, 105, 101, 108, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 79, 112, 116, 105, 111, 110, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 102, 97, 117, 108, 116, 69, 110, 99, 111, 100, 105, 110, 103, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 70, 105, 101, 108, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 70, 105, 101, 108, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 69, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 73, 110, 118, 101, 114, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 70, 105, 101, 108, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 54, 52, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 116, 105, 111, 110, 83, 101, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 105, 100, 66, 105, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 114, 109, 97, 108, 105, 122, 101, 100, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 99, 105, 109, 97, 108, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 117, 114, 97, 116, 105, 111, 110, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 101, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 117, 114, 97, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 116, 99, 84, 105, 109, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 90, 111, 110, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 121, 108, 105, 103, 104, 116, 83, 97, 118, 105, 110, 103, 73, 110, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 101, 103, 101, 114, 73, 100, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 65, 110, 100, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 97, 116, 101, 119, 97, 121, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 116, 117, 114, 110, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 100, 105, 116, 69, 110, 116, 114, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 111, 117, 116, 72, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 105, 110, 103, 84, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 84, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 105, 110, 103, 84, 97, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 101, 114, 115, 105, 111, 110, 84, 105, 109, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 70, 97, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 108, 101, 115, 115, 73, 110, 118, 111, 107, 101, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 114, 105, 115, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 108, 101, 115, 115, 73, 110, 118, 111, 107, 101, 82, 101, 115, 112, 111, 110, 115, 101, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 79, 110, 78, 101, 116, 119, 111, 114, 107, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 111, 114, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 79, 110, 78, 101, 116, 119, 111, 114, 107, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 105, 110, 103, 82, 101, 99, 111, 114, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 99, 111, 114, 100, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 121, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 121, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 121, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 79, 110, 78, 101, 116, 119, 111, 114, 107, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 67, 111, 117, 110, 116, 101, 114, 82, 101, 115, 101, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 101, 114, 79, 110, 78, 101, 116, 119, 111, 114, 107, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 73, 110, 115, 116, 97, 110, 99, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 97, 108, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 65, 110, 100, 69, 110, 99, 114, 121, 112, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 111, 110, 121, 109, 111, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 100, 84, 111, 107, 101, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 84, 111, 107, 101, 110, 80, 111, 108, 105, 99, 121, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 100, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 84, 111, 107, 101, 110, 80, 111, 108, 105, 99, 121, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 116, 69, 110, 100, 112, 111, 105, 110, 116, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 116, 69, 110, 100, 112, 111, 105, 110, 116, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 83, 101, 114, 118, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 97, 116, 101, 119, 97, 121, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 112, 104, 111, 114, 101, 70, 105, 108, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 79, 110, 108, 105, 110, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 83, 101, 114, 118, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 100, 110, 115, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 100, 110, 115, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 50, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 83, 101, 114, 118, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 50, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 110, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 104, 97, 110, 110, 101, 108, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 104, 97, 110, 110, 101, 108, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 107, 101, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 100, 65, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 110, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 80, 114, 111, 116, 111, 99, 111, 108, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 110, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 114, 111, 116, 111, 99, 111, 108, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 104, 97, 110, 110, 101, 108, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 101, 100, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 103, 111, 114, 105, 116, 104, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 115, 112, 111, 110, 115, 101, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 101, 100, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 113, 117, 101, 115, 116, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 111, 110, 121, 109, 111, 117, 115, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 115, 115, 119, 111, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 114, 121, 112, 116, 105, 111, 110, 65, 108, 103, 111, 114, 105, 116, 104, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 88, 53, 48, 57, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 100, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 107, 101, 110, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 114, 121, 112, 116, 105, 111, 110, 65, 108, 103, 111, 114, 105, 116, 104, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 115, 97, 69, 110, 99, 114, 121, 112, 116, 101, 100, 83, 101, 99, 114, 101, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 99, 99, 69, 110, 99, 114, 121, 112, 116, 101, 100, 83, 101, 99, 114, 101, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 116, 105, 118, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 101, 100, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 84, 111, 107, 101, 110, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 116, 105, 118, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 110, 99, 101, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 110, 99, 101, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 97, 110, 99, 101, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 48, 57, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 49, 57, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 51, 56, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 55, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 53, 53, 51, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 51, 49, 48, 55, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 50, 49, 52, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 50, 52, 50, 56, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 52, 56, 53, 55, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 57, 55, 49, 53, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 49, 57, 52, 51, 48, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 51, 56, 56, 54, 48, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 55, 55, 55, 50, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 51, 53, 53, 52, 52, 51, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 101, 78, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 49, 50, 50, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 49, 51, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 51, 50, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 55, 49, 51, 56, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 56, 54, 48, 48, 52, 51, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 54, 51, 50, 53, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 51, 55, 48, 54, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 49, 51, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 110, 101, 114, 105, 99, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 110, 101, 114, 105, 99, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 71, 101, 110, 101, 114, 105, 99, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 101, 110, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 78, 101, 119, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 100, 100, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 65, 100, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 65, 100, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 84, 97, 114, 103, 101, 116, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 66, 105, 100, 105, 114, 101, 99, 116, 105, 111, 110, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 48, 57, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 49, 57, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 51, 56, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 55, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 53, 53, 51, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 51, 49, 48, 55, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 50, 49, 52, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 50, 52, 50, 56, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 52, 56, 53, 55, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 70, 111, 114, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 57, 55, 49, 53, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 49, 57, 52, 51, 48, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 51, 56, 56, 54, 48, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 55, 55, 55, 50, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 69, 120, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 51, 53, 53, 52, 52, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 68, 105, 114, 101, 99, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 70, 111, 114, 119, 97, 114, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 111, 116, 104, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 97, 108, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 68, 105, 114, 101, 99, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 68, 105, 114, 101, 99, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 99, 108, 117, 100, 101, 83, 117, 98, 116, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 110, 102, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 73, 110, 102, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 48, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 86, 105, 101, 119, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 77, 97, 120, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 80, 101, 114, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 101, 120, 116, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 101, 97, 115, 101, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 101, 120, 116, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 73, 110, 118, 101, 114, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 99, 108, 117, 100, 101, 83, 117, 98, 116, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 105, 110, 103, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 84, 97, 114, 103, 101, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 97, 105, 110, 105, 110, 103, 80, 97, 116, 104, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 84, 97, 114, 103, 101, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 108, 97, 116, 101, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 84, 111, 78, 111, 100, 101, 73, 100, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 108, 97, 116, 101, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 84, 111, 78, 111, 100, 101, 73, 100, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 82, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 103, 105, 115, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 117, 110, 116, 101, 114, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 82, 97, 110, 103, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 116, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 66, 105, 110, 97, 114, 121, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 66, 117, 102, 102, 101, 114, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 104, 97, 110, 110, 101, 108, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 99, 108, 117, 100, 101, 83, 117, 98, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 81, 117, 101, 114, 121, 68, 97, 116, 97, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 116, 111, 114, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 113, 117, 97, 108, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 78, 117, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 101, 97, 116, 101, 114, 84, 104, 97, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 101, 115, 115, 84, 104, 97, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 101, 97, 116, 101, 114, 84, 104, 97, 110, 79, 114, 69, 113, 117, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 101, 115, 115, 84, 104, 97, 110, 79, 114, 69, 113, 117, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 105, 107, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 55, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 101, 116, 119, 101, 101, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 76, 105, 115, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 57, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 115, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 86, 105, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 102, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 101, 100, 84, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 105, 116, 119, 105, 115, 101, 65, 110, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 105, 116, 119, 105, 115, 101, 79, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 55, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 116, 111, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 76, 105, 116, 101, 114, 97, 108, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 105, 97, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 110, 100, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 110, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 70, 105, 114, 115, 116, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 86, 105, 101, 119, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 68, 97, 116, 97, 83, 101, 116, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 70, 105, 114, 115, 116, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 78, 101, 120, 116, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 101, 97, 115, 101, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 78, 101, 120, 116, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 111, 116, 104, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 105, 116, 104, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 97, 108, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 65, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 69, 118, 101, 110, 116, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 86, 97, 108, 117, 101, 115, 80, 101, 114, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 97, 119, 77, 111, 100, 105, 102, 105, 101, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 82, 101, 97, 100, 77, 111, 100, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 86, 97, 108, 117, 101, 115, 80, 101, 114, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 116, 117, 114, 110, 66, 111, 117, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 80, 114, 111, 99, 101, 115, 115, 101, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 65, 116, 84, 105, 109, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 83, 105, 109, 112, 108, 101, 66, 111, 117, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 68, 97, 116, 97, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 77, 111, 100, 105, 102, 105, 101, 100, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 101, 97, 115, 101, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 86, 97, 108, 117, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 87, 114, 105, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 87, 114, 105, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 87, 114, 105, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 101, 114, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 108, 97, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 101, 114, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 108, 97, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 68, 97, 116, 97, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 73, 110, 115, 101, 114, 116, 82, 101, 112, 108, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 73, 110, 115, 101, 114, 116, 82, 101, 112, 108, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 69, 118, 101, 110, 116, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 73, 110, 115, 101, 114, 116, 82, 101, 112, 108, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 97, 119, 77, 111, 100, 105, 102, 105, 101, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 68, 101, 108, 101, 116, 101, 77, 111, 100, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 65, 116, 84, 105, 109, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 69, 118, 101, 110, 116, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 101, 116, 104, 111, 100, 115, 84, 111, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 115, 84, 111, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 101, 116, 104, 111, 100, 115, 84, 111, 67, 97, 108, 108, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 111, 114, 116, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 84, 114, 105, 103, 103, 101, 114, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 86, 97, 108, 117, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 98, 115, 111, 108, 117, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 105, 103, 103, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 84, 114, 105, 103, 103, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 104, 101, 114, 101, 67, 108, 97, 117, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 68, 101, 102, 97, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 101, 97, 116, 85, 110, 99, 101, 114, 116, 97, 105, 110, 65, 115, 66, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 68, 97, 116, 97, 66, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 68, 97, 116, 97, 71, 111, 111, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 83, 108, 111, 112, 101, 100, 69, 120, 116, 114, 97, 112, 111, 108, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 104, 101, 114, 101, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 97, 114, 100, 79, 108, 100, 101, 115, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 116, 101, 109, 84, 111, 77, 111, 110, 105, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 81, 117, 101, 117, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 67, 114, 101, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 116, 101, 109, 115, 84, 111, 67, 114, 101, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 67, 114, 101, 97, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 81, 117, 101, 117, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 77, 111, 100, 105, 102, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 116, 101, 109, 115, 84, 111, 77, 111, 100, 105, 102, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 113, 117, 101, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 77, 111, 100, 105, 102, 121, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 73, 116, 101, 109, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 105, 110, 107, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 65, 100, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 82, 101, 109, 111, 118, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 105, 110, 107, 115, 84, 111, 82, 101, 109, 111, 118, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 82, 101, 109, 111, 118, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 100, 100, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 100, 100, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 100, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 100, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 80, 101, 114, 80, 117, 98, 108, 105, 115, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 80, 101, 114, 80, 117, 98, 108, 105, 115, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 77, 111, 100, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 77, 111, 100, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 76, 105, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 104, 97, 110, 103, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 114, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 116, 114, 97, 110, 115, 109, 105, 116, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 110, 100, 73, 110, 105, 116, 105, 97, 108, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 114, 97, 110, 115, 102, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 73, 110, 102, 111, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 110, 117, 102, 97, 99, 116, 117, 114, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 102, 116, 119, 97, 114, 101, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 68, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 100, 117, 110, 100, 97, 110, 99, 121, 83, 117, 112, 112, 111, 114, 116, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 108, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 97, 114, 109, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 111, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 97, 114, 101, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 111, 116, 65, 110, 100, 77, 105, 114, 114, 111, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 117, 110, 110, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 70, 97, 105, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 115, 112, 101, 110, 100, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 104, 117, 116, 100, 111, 119, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 101, 115, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 70, 97, 117, 108, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 107, 110, 111, 119, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 55, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 100, 117, 110, 100, 97, 110, 116, 83, 101, 114, 118, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 101, 116, 119, 111, 114, 107, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 101, 116, 119, 111, 114, 107, 80, 97, 116, 104, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 83, 117, 109, 109, 97, 114, 121, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 86, 105, 101, 119, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 109, 117, 108, 97, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 82, 101, 106, 101, 99, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 106, 101, 99, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 65, 98, 111, 114, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 109, 117, 108, 97, 116, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 82, 101, 106, 101, 99, 116, 101, 100, 82, 101, 113, 117, 101, 115, 116, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 106, 101, 99, 116, 101, 100, 82, 101, 113, 117, 101, 115, 116, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 117, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 117, 105, 108, 100, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 111, 110, 100, 115, 84, 105, 108, 108, 83, 104, 117, 116, 100, 111, 119, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 104, 117, 116, 100, 111, 119, 110, 82, 101, 97, 115, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 116, 117, 97, 108, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 115, 112, 111, 110, 115, 101, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 76, 97, 115, 116, 67, 111, 110, 116, 97, 99, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 115, 73, 110, 81, 117, 101, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 116, 97, 108, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 97, 117, 116, 104, 111, 114, 105, 122, 101, 100, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 77, 111, 100, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 101, 120, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 108, 97, 116, 101, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 84, 111, 78, 111, 100, 101, 73, 100, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 70, 105, 114, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 78, 101, 120, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 83, 101, 99, 117, 114, 105, 116, 121, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 79, 102, 83, 101, 115, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 77, 101, 99, 104, 97, 110, 105, 115, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 116, 111, 99, 111, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 116, 97, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 114, 114, 111, 114, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 80, 101, 114, 80, 117, 98, 108, 105, 115, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 77, 101, 115, 115, 97, 103, 101, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 77, 101, 115, 115, 97, 103, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 114, 101, 100, 84, 111, 65, 108, 116, 67, 108, 105, 101, 110, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 114, 101, 100, 84, 111, 83, 97, 109, 101, 67, 108, 105, 101, 110, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 116, 101, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 97, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 100, 77, 101, 115, 115, 97, 103, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 97, 114, 100, 101, 100, 77, 101, 115, 115, 97, 103, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 81, 117, 101, 117, 101, 79, 118, 101, 114, 102, 108, 111, 119, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 120, 116, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 81, 117, 101, 117, 101, 79, 118, 101, 114, 70, 108, 111, 119, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 101, 108, 67, 104, 97, 110, 103, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 86, 101, 114, 98, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 100, 100, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 68, 101, 108, 101, 116, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 65, 100, 100, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 68, 101, 108, 101, 116, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 67, 104, 97, 110, 103, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 101, 108, 67, 104, 97, 110, 103, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 101, 114, 98, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 110, 116, 105, 99, 67, 104, 97, 110, 103, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 97, 110, 103, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 119, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 103, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 85, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 105, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 83, 99, 97, 108, 101, 69, 110, 117, 109, 101, 114, 97, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 105, 110, 101, 97, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 109, 112, 108, 101, 120, 78, 117, 109, 98, 101, 114, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 105, 110, 97, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 111, 117, 98, 108, 101, 67, 111, 109, 112, 108, 101, 120, 78, 117, 109, 98, 101, 114, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 105, 110, 97, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 85, 110, 105, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 85, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 85, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 97, 110, 103, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 116, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 83, 99, 97, 108, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 120, 105, 115, 83, 99, 97, 108, 101, 69, 110, 117, 109, 101, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 120, 105, 115, 83, 116, 101, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 83, 116, 101, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 120, 105, 115, 83, 116, 101, 112, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 88, 86, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 103, 114, 97, 109, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 67, 108, 105, 101, 110, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 111, 99, 97, 116, 105, 111, 110, 67, 114, 101, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 84, 114, 97, 110, 115, 105, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 82, 101, 116, 117, 114, 110, 83, 116, 97, 116, 117, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 97, 116, 117, 115, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 103, 114, 97, 109, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 50, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 67, 108, 105, 101, 110, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 111, 99, 97, 116, 105, 111, 110, 67, 114, 101, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 84, 114, 97, 110, 115, 105, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 82, 101, 116, 117, 114, 110, 83, 116, 97, 116, 117, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 97, 116, 117, 115, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 99, 101, 112, 116, 105, 111, 110, 68, 101, 118, 105, 97, 116, 105, 111, 110, 70, 111, 114, 109, 97, 116, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 98, 115, 111, 108, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 79, 102, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 79, 102, 82, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 79, 102, 69, 85, 82, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 107, 110, 111, 119, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 60, 47, 111, 112, 99, 58, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 62}; + + -static UA_StatusCode function_namespace0_generated_207_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_185_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 15); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU); UA_ByteString *variablenode_ns_0_i_7617_variant_DataContents = UA_ByteString_new(); if (!variablenode_ns_0_i_7617_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; UA_ByteString_init(variablenode_ns_0_i_7617_variant_DataContents); -*variablenode_ns_0_i_7617_variant_DataContents = UA_BYTESTRING_NULL; +variablenode_ns_0_i_7617_variant_DataContents->length = 177218; +variablenode_ns_0_i_7617_variant_DataContents->data = (UA_Byte *)(void*)(uintptr_t)variablenode_ns_0_i_7617_variant_DataContents_byteArray; UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7617_variant_DataContents, &UA_TYPES[UA_TYPES_BYTESTRING]); attr.displayName = UA_LOCALIZEDTEXT("", "Opc.Ua"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 7617), -UA_NODEID_NUMERIC(ns[0], 93), -UA_NODEID_NUMERIC(ns[0], 47), +UA_NODEID_NUMERIC(ns[0], 7617LU), +UA_NODEID_NUMERIC(ns[0], 93LU), +UA_NODEID_NUMERIC(ns[0], 47LU), UA_QUALIFIEDNAME(ns[0], "Opc.Ua"), -UA_NODEID_NUMERIC(ns[0], 72), +UA_NODEID_NUMERIC(ns[0], 72LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); variablenode_ns_0_i_7617_variant_DataContents->data = NULL; variablenode_ns_0_i_7617_variant_DataContents->length = 0; @@ -51762,267 +56874,267 @@ UA_ByteString_delete(variablenode_ns_0_i_7617_variant_DataContents); return retVal; } -static UA_StatusCode function_namespace0_generated_207_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_185_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 7617) +UA_NODEID_NUMERIC(ns[0], 7617LU) ); } /* NamespaceUri - ns=0;i=107 */ -static UA_StatusCode function_namespace0_generated_208_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_186_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceUri"); #ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS attr.description = UA_LOCALIZEDTEXT("", "A URI that uniquely identifies the dictionary."); #endif retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 107), -UA_NODEID_NUMERIC(ns[0], 72), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 107LU), +UA_NODEID_NUMERIC(ns[0], 72LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "NamespaceUri"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 107), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80), true); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 107LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true); return retVal; } -static UA_StatusCode function_namespace0_generated_208_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_186_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 107) +UA_NODEID_NUMERIC(ns[0], 107LU) ); } /* DataTypeVersion - ns=0;i=106 */ -static UA_StatusCode function_namespace0_generated_209_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_187_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 106), -UA_NODEID_NUMERIC(ns[0], 72), -UA_NODEID_NUMERIC(ns[0], 46), +UA_NODEID_NUMERIC(ns[0], 106LU), +UA_NODEID_NUMERIC(ns[0], 72LU), +UA_NODEID_NUMERIC(ns[0], 46LU), UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 106), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80), true); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 106LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true); return retVal; } -static UA_StatusCode function_namespace0_generated_209_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_187_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 106) +UA_NODEID_NUMERIC(ns[0], 106LU) ); } /* DataTypeDescriptionType - ns=0;i=69 */ -static UA_StatusCode function_namespace0_generated_210_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_188_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDescriptionType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, -UA_NODEID_NUMERIC(ns[0], 69), -UA_NODEID_NUMERIC(ns[0], 63), -UA_NODEID_NUMERIC(ns[0], 45), +UA_NODEID_NUMERIC(ns[0], 69LU), +UA_NODEID_NUMERIC(ns[0], 63LU), +UA_NODEID_NUMERIC(ns[0], 45LU), UA_QUALIFIEDNAME(ns[0], "DataTypeDescriptionType"), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_210_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_188_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 69) +UA_NODEID_NUMERIC(ns[0], 69LU) ); } -/* DictionaryFragment - ns=0;i=105 */ +/* EnumValueType - ns=0;i=7656 */ -static UA_StatusCode function_namespace0_generated_211_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_189_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 15); -attr.displayName = UA_LOCALIZEDTEXT("", "DictionaryFragment"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +UA_String *variablenode_ns_0_i_7656_variant_DataContents = UA_String_new(); +if (!variablenode_ns_0_i_7656_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_String_init(variablenode_ns_0_i_7656_variant_DataContents); +*variablenode_ns_0_i_7656_variant_DataContents = UA_STRING_ALLOC("EnumValueType"); +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7656_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 105), -UA_NODEID_NUMERIC(ns[0], 69), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "DictionaryFragment"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 7656LU), +UA_NODEID_NUMERIC(ns[0], 7617LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "EnumValueType"), +UA_NODEID_NUMERIC(ns[0], 69LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 105), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80), true); +UA_String_delete(variablenode_ns_0_i_7656_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7656LU), UA_NODEID_NUMERIC(ns[0], 39LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8251LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_211_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_189_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 105) +UA_NODEID_NUMERIC(ns[0], 7656LU) ); } -/* EnumValueType - ns=0;i=7656 */ +/* Argument - ns=0;i=7650 */ -static UA_StatusCode function_namespace0_generated_212_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_190_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -UA_String *variablenode_ns_0_i_7656_variant_DataContents = UA_String_new(); -if (!variablenode_ns_0_i_7656_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; -UA_String_init(variablenode_ns_0_i_7656_variant_DataContents); -*variablenode_ns_0_i_7656_variant_DataContents = UA_STRING_ALLOC("EnumValueType"); -UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7656_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]); -attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +UA_String *variablenode_ns_0_i_7650_variant_DataContents = UA_String_new(); +if (!variablenode_ns_0_i_7650_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +UA_String_init(variablenode_ns_0_i_7650_variant_DataContents); +*variablenode_ns_0_i_7650_variant_DataContents = UA_STRING_ALLOC("Argument"); +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7650_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "Argument"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 7656), -UA_NODEID_NUMERIC(ns[0], 7617), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "EnumValueType"), -UA_NODEID_NUMERIC(ns[0], 69), +UA_NODEID_NUMERIC(ns[0], 7650LU), +UA_NODEID_NUMERIC(ns[0], 7617LU), +UA_NODEID_NUMERIC(ns[0], 47LU), +UA_QUALIFIEDNAME(ns[0], "Argument"), +UA_NODEID_NUMERIC(ns[0], 69LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -UA_String_delete(variablenode_ns_0_i_7656_variant_DataContents); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7656), UA_NODEID_NUMERIC(ns[0], 39), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8251), false); +UA_String_delete(variablenode_ns_0_i_7650_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7650LU), UA_NODEID_NUMERIC(ns[0], 39LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 298LU), false); return retVal; } -static UA_StatusCode function_namespace0_generated_212_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_190_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 7656) +UA_NODEID_NUMERIC(ns[0], 7650LU) ); } -/* DataTypeVersion - ns=0;i=104 */ +/* DictionaryFragment - ns=0;i=105 */ -static UA_StatusCode function_namespace0_generated_213_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_191_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU); +attr.displayName = UA_LOCALIZEDTEXT("", "DictionaryFragment"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 104), -UA_NODEID_NUMERIC(ns[0], 69), -UA_NODEID_NUMERIC(ns[0], 46), -UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"), -UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 105LU), +UA_NODEID_NUMERIC(ns[0], 69LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "DictionaryFragment"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 104), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80), true); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 105LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true); return retVal; } -static UA_StatusCode function_namespace0_generated_213_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_191_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 104) +UA_NODEID_NUMERIC(ns[0], 105LU) ); } -/* Argument - ns=0;i=7650 */ +/* DataTypeVersion - ns=0;i=104 */ -static UA_StatusCode function_namespace0_generated_214_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_192_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.minimumSamplingInterval = 0.000000; attr.userAccessLevel = 1; attr.accessLevel = 1; /* Value rank inherited */ -attr.valueRank = -1; -attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); -UA_String *variablenode_ns_0_i_7650_variant_DataContents = UA_String_new(); -if (!variablenode_ns_0_i_7650_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; -UA_String_init(variablenode_ns_0_i_7650_variant_DataContents); -*variablenode_ns_0_i_7650_variant_DataContents = UA_STRING_ALLOC("Argument"); -UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7650_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]); -attr.displayName = UA_LOCALIZEDTEXT("", "Argument"); +attr.valueRank = -2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU); +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, -UA_NODEID_NUMERIC(ns[0], 7650), -UA_NODEID_NUMERIC(ns[0], 7617), -UA_NODEID_NUMERIC(ns[0], 47), -UA_QUALIFIEDNAME(ns[0], "Argument"), -UA_NODEID_NUMERIC(ns[0], 69), +UA_NODEID_NUMERIC(ns[0], 104LU), +UA_NODEID_NUMERIC(ns[0], 69LU), +UA_NODEID_NUMERIC(ns[0], 46LU), +UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"), +UA_NODEID_NUMERIC(ns[0], 68LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); -UA_String_delete(variablenode_ns_0_i_7650_variant_DataContents); -retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7650), UA_NODEID_NUMERIC(ns[0], 39), UA_EXPANDEDNODEID_NUMERIC(ns[0], 298), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 104LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true); return retVal; } -static UA_StatusCode function_namespace0_generated_214_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_192_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 7650) +UA_NODEID_NUMERIC(ns[0], 104LU) ); } /* Default XML - ns=0;i=3063 */ -static UA_StatusCode function_namespace0_generated_215_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_193_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Default XML"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 3063), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 3063LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), UA_QUALIFIEDNAME(ns[0], "Default XML"), -UA_NODEID_NUMERIC(ns[0], 58), +UA_NODEID_NUMERIC(ns[0], 58LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_215_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_193_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3063) +UA_NODEID_NUMERIC(ns[0], 3063LU) ); } /* Default Binary - ns=0;i=3062 */ -static UA_StatusCode function_namespace0_generated_216_begin(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_194_begin(UA_Server *server, UA_UInt16* ns) { UA_StatusCode retVal = UA_STATUSCODE_GOOD; UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary"); retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, -UA_NODEID_NUMERIC(ns[0], 3062), -UA_NODEID_NUMERIC(ns[0], 0), -UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 3062LU), +UA_NODEID_NUMERIC(ns[0], 0LU), +UA_NODEID_NUMERIC(ns[0], 0LU), UA_QUALIFIEDNAME(ns[0], "Default Binary"), -UA_NODEID_NUMERIC(ns[0], 58), +UA_NODEID_NUMERIC(ns[0], 58LU), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); return retVal; } -static UA_StatusCode function_namespace0_generated_216_finish(UA_Server *server, UA_UInt16* ns) { +static UA_StatusCode function_namespace0_generated_194_finish(UA_Server *server, UA_UInt16* ns) { return UA_Server_addNode_finish(server, -UA_NODEID_NUMERIC(ns[0], 3062) +UA_NODEID_NUMERIC(ns[0], 3062LU) ); } @@ -52031,451 +57143,407 @@ UA_StatusCode retVal = UA_STATUSCODE_GOOD; /* Use namespace ids generated by the server */ UA_UInt16 ns[1]; ns[0] = UA_Server_addNamespace(server, "http://opcfoundation.org/UA/"); -bool dummy = ( -!(retVal = function_namespace0_generated_0_begin(server, ns)) && -!(retVal = function_namespace0_generated_1_begin(server, ns)) && -!(retVal = function_namespace0_generated_2_begin(server, ns)) && -!(retVal = function_namespace0_generated_3_begin(server, ns)) && -!(retVal = function_namespace0_generated_4_begin(server, ns)) && -!(retVal = function_namespace0_generated_5_begin(server, ns)) && -!(retVal = function_namespace0_generated_6_begin(server, ns)) && -!(retVal = function_namespace0_generated_7_begin(server, ns)) && -!(retVal = function_namespace0_generated_8_begin(server, ns)) && -!(retVal = function_namespace0_generated_9_begin(server, ns)) && -!(retVal = function_namespace0_generated_10_begin(server, ns)) && -!(retVal = function_namespace0_generated_11_begin(server, ns)) && -!(retVal = function_namespace0_generated_12_begin(server, ns)) && -!(retVal = function_namespace0_generated_13_begin(server, ns)) && -!(retVal = function_namespace0_generated_14_begin(server, ns)) && -!(retVal = function_namespace0_generated_15_begin(server, ns)) && -!(retVal = function_namespace0_generated_16_begin(server, ns)) && -!(retVal = function_namespace0_generated_17_begin(server, ns)) && -!(retVal = function_namespace0_generated_18_begin(server, ns)) && -!(retVal = function_namespace0_generated_19_begin(server, ns)) && -!(retVal = function_namespace0_generated_20_begin(server, ns)) && -!(retVal = function_namespace0_generated_21_begin(server, ns)) && -!(retVal = function_namespace0_generated_22_begin(server, ns)) && -!(retVal = function_namespace0_generated_23_begin(server, ns)) && -!(retVal = function_namespace0_generated_24_begin(server, ns)) && -!(retVal = function_namespace0_generated_25_begin(server, ns)) && -!(retVal = function_namespace0_generated_26_begin(server, ns)) && -!(retVal = function_namespace0_generated_27_begin(server, ns)) && -!(retVal = function_namespace0_generated_28_begin(server, ns)) && -!(retVal = function_namespace0_generated_29_begin(server, ns)) && -!(retVal = function_namespace0_generated_30_begin(server, ns)) && -!(retVal = function_namespace0_generated_31_begin(server, ns)) && -!(retVal = function_namespace0_generated_32_begin(server, ns)) && -!(retVal = function_namespace0_generated_33_begin(server, ns)) && -!(retVal = function_namespace0_generated_34_begin(server, ns)) && -!(retVal = function_namespace0_generated_35_begin(server, ns)) && -!(retVal = function_namespace0_generated_36_begin(server, ns)) && -!(retVal = function_namespace0_generated_37_begin(server, ns)) && -!(retVal = function_namespace0_generated_38_begin(server, ns)) && -!(retVal = function_namespace0_generated_39_begin(server, ns)) && -!(retVal = function_namespace0_generated_40_begin(server, ns)) && -!(retVal = function_namespace0_generated_41_begin(server, ns)) && -!(retVal = function_namespace0_generated_42_begin(server, ns)) && -!(retVal = function_namespace0_generated_43_begin(server, ns)) && -!(retVal = function_namespace0_generated_44_begin(server, ns)) && -!(retVal = function_namespace0_generated_45_begin(server, ns)) && -!(retVal = function_namespace0_generated_46_begin(server, ns)) && -!(retVal = function_namespace0_generated_47_begin(server, ns)) && -!(retVal = function_namespace0_generated_48_begin(server, ns)) && -!(retVal = function_namespace0_generated_49_begin(server, ns)) && -!(retVal = function_namespace0_generated_50_begin(server, ns)) && -!(retVal = function_namespace0_generated_51_begin(server, ns)) && -!(retVal = function_namespace0_generated_52_begin(server, ns)) && -!(retVal = function_namespace0_generated_53_begin(server, ns)) && -!(retVal = function_namespace0_generated_54_begin(server, ns)) && -!(retVal = function_namespace0_generated_55_begin(server, ns)) && -!(retVal = function_namespace0_generated_56_begin(server, ns)) && -!(retVal = function_namespace0_generated_57_begin(server, ns)) && -!(retVal = function_namespace0_generated_58_begin(server, ns)) && -!(retVal = function_namespace0_generated_59_begin(server, ns)) && -!(retVal = function_namespace0_generated_60_begin(server, ns)) && -!(retVal = function_namespace0_generated_61_begin(server, ns)) && -!(retVal = function_namespace0_generated_62_begin(server, ns)) && -!(retVal = function_namespace0_generated_63_begin(server, ns)) && -!(retVal = function_namespace0_generated_64_begin(server, ns)) && -!(retVal = function_namespace0_generated_65_begin(server, ns)) && -!(retVal = function_namespace0_generated_66_begin(server, ns)) && -!(retVal = function_namespace0_generated_67_begin(server, ns)) && -!(retVal = function_namespace0_generated_68_begin(server, ns)) && -!(retVal = function_namespace0_generated_69_begin(server, ns)) && -!(retVal = function_namespace0_generated_70_begin(server, ns)) && -!(retVal = function_namespace0_generated_71_begin(server, ns)) && -!(retVal = function_namespace0_generated_72_begin(server, ns)) && -!(retVal = function_namespace0_generated_73_begin(server, ns)) && -!(retVal = function_namespace0_generated_74_begin(server, ns)) && -!(retVal = function_namespace0_generated_75_begin(server, ns)) && -!(retVal = function_namespace0_generated_76_begin(server, ns)) && -!(retVal = function_namespace0_generated_77_begin(server, ns)) && -!(retVal = function_namespace0_generated_78_begin(server, ns)) && -!(retVal = function_namespace0_generated_79_begin(server, ns)) && -!(retVal = function_namespace0_generated_80_begin(server, ns)) && -!(retVal = function_namespace0_generated_81_begin(server, ns)) && -!(retVal = function_namespace0_generated_82_begin(server, ns)) && -!(retVal = function_namespace0_generated_83_begin(server, ns)) && -!(retVal = function_namespace0_generated_84_begin(server, ns)) && -!(retVal = function_namespace0_generated_85_begin(server, ns)) && -!(retVal = function_namespace0_generated_86_begin(server, ns)) && -!(retVal = function_namespace0_generated_87_begin(server, ns)) && -!(retVal = function_namespace0_generated_88_begin(server, ns)) && -!(retVal = function_namespace0_generated_89_begin(server, ns)) && -!(retVal = function_namespace0_generated_90_begin(server, ns)) && -!(retVal = function_namespace0_generated_91_begin(server, ns)) && -!(retVal = function_namespace0_generated_92_begin(server, ns)) && -!(retVal = function_namespace0_generated_93_begin(server, ns)) && -!(retVal = function_namespace0_generated_94_begin(server, ns)) && -!(retVal = function_namespace0_generated_95_begin(server, ns)) && -!(retVal = function_namespace0_generated_96_begin(server, ns)) && -!(retVal = function_namespace0_generated_97_begin(server, ns)) && -!(retVal = function_namespace0_generated_98_begin(server, ns)) && -!(retVal = function_namespace0_generated_99_begin(server, ns)) && -!(retVal = function_namespace0_generated_100_begin(server, ns)) && -!(retVal = function_namespace0_generated_101_begin(server, ns)) && -!(retVal = function_namespace0_generated_102_begin(server, ns)) && -!(retVal = function_namespace0_generated_103_begin(server, ns)) && -!(retVal = function_namespace0_generated_104_begin(server, ns)) && -!(retVal = function_namespace0_generated_105_begin(server, ns)) && -!(retVal = function_namespace0_generated_106_begin(server, ns)) && -!(retVal = function_namespace0_generated_107_begin(server, ns)) && -!(retVal = function_namespace0_generated_108_begin(server, ns)) && -!(retVal = function_namespace0_generated_109_begin(server, ns)) && -!(retVal = function_namespace0_generated_110_begin(server, ns)) && -!(retVal = function_namespace0_generated_111_begin(server, ns)) && -!(retVal = function_namespace0_generated_112_begin(server, ns)) && -!(retVal = function_namespace0_generated_113_begin(server, ns)) && -!(retVal = function_namespace0_generated_114_begin(server, ns)) && -!(retVal = function_namespace0_generated_115_begin(server, ns)) && -!(retVal = function_namespace0_generated_116_begin(server, ns)) && -!(retVal = function_namespace0_generated_117_begin(server, ns)) && -!(retVal = function_namespace0_generated_118_begin(server, ns)) && -!(retVal = function_namespace0_generated_119_begin(server, ns)) && -!(retVal = function_namespace0_generated_120_begin(server, ns)) && -!(retVal = function_namespace0_generated_121_begin(server, ns)) && -!(retVal = function_namespace0_generated_122_begin(server, ns)) && -!(retVal = function_namespace0_generated_123_begin(server, ns)) && -!(retVal = function_namespace0_generated_124_begin(server, ns)) && -!(retVal = function_namespace0_generated_125_begin(server, ns)) && -!(retVal = function_namespace0_generated_126_begin(server, ns)) && -!(retVal = function_namespace0_generated_127_begin(server, ns)) && -!(retVal = function_namespace0_generated_128_begin(server, ns)) && -!(retVal = function_namespace0_generated_129_begin(server, ns)) && -!(retVal = function_namespace0_generated_130_begin(server, ns)) && -!(retVal = function_namespace0_generated_131_begin(server, ns)) && -!(retVal = function_namespace0_generated_132_begin(server, ns)) && -!(retVal = function_namespace0_generated_133_begin(server, ns)) && -!(retVal = function_namespace0_generated_134_begin(server, ns)) && -!(retVal = function_namespace0_generated_135_begin(server, ns)) && -!(retVal = function_namespace0_generated_136_begin(server, ns)) && -!(retVal = function_namespace0_generated_137_begin(server, ns)) && -!(retVal = function_namespace0_generated_138_begin(server, ns)) && -!(retVal = function_namespace0_generated_139_begin(server, ns)) && -!(retVal = function_namespace0_generated_140_begin(server, ns)) && -!(retVal = function_namespace0_generated_141_begin(server, ns)) && -!(retVal = function_namespace0_generated_142_begin(server, ns)) && -!(retVal = function_namespace0_generated_143_begin(server, ns)) && -!(retVal = function_namespace0_generated_144_begin(server, ns)) && -!(retVal = function_namespace0_generated_145_begin(server, ns)) && -!(retVal = function_namespace0_generated_146_begin(server, ns)) && -!(retVal = function_namespace0_generated_147_begin(server, ns)) && -!(retVal = function_namespace0_generated_148_begin(server, ns)) && -!(retVal = function_namespace0_generated_149_begin(server, ns)) && -!(retVal = function_namespace0_generated_150_begin(server, ns)) && -!(retVal = function_namespace0_generated_151_begin(server, ns)) && -!(retVal = function_namespace0_generated_152_begin(server, ns)) && -!(retVal = function_namespace0_generated_153_begin(server, ns)) && -!(retVal = function_namespace0_generated_154_begin(server, ns)) && -!(retVal = function_namespace0_generated_155_begin(server, ns)) && -!(retVal = function_namespace0_generated_156_begin(server, ns)) && -!(retVal = function_namespace0_generated_157_begin(server, ns)) && -!(retVal = function_namespace0_generated_158_begin(server, ns)) && -!(retVal = function_namespace0_generated_159_begin(server, ns)) && -!(retVal = function_namespace0_generated_160_begin(server, ns)) && -!(retVal = function_namespace0_generated_161_begin(server, ns)) && -!(retVal = function_namespace0_generated_162_begin(server, ns)) && -!(retVal = function_namespace0_generated_163_begin(server, ns)) && -!(retVal = function_namespace0_generated_164_begin(server, ns)) && -!(retVal = function_namespace0_generated_165_begin(server, ns)) && -!(retVal = function_namespace0_generated_166_begin(server, ns)) && -!(retVal = function_namespace0_generated_167_begin(server, ns)) && -!(retVal = function_namespace0_generated_168_begin(server, ns)) && -!(retVal = function_namespace0_generated_169_begin(server, ns)) && -!(retVal = function_namespace0_generated_170_begin(server, ns)) && -!(retVal = function_namespace0_generated_171_begin(server, ns)) && -!(retVal = function_namespace0_generated_172_begin(server, ns)) && -!(retVal = function_namespace0_generated_173_begin(server, ns)) && -!(retVal = function_namespace0_generated_174_begin(server, ns)) && -!(retVal = function_namespace0_generated_175_begin(server, ns)) && -!(retVal = function_namespace0_generated_176_begin(server, ns)) && -!(retVal = function_namespace0_generated_177_begin(server, ns)) && -!(retVal = function_namespace0_generated_178_begin(server, ns)) && -!(retVal = function_namespace0_generated_179_begin(server, ns)) && -!(retVal = function_namespace0_generated_180_begin(server, ns)) && -!(retVal = function_namespace0_generated_181_begin(server, ns)) && -!(retVal = function_namespace0_generated_182_begin(server, ns)) && -!(retVal = function_namespace0_generated_183_begin(server, ns)) && -!(retVal = function_namespace0_generated_184_begin(server, ns)) && -!(retVal = function_namespace0_generated_185_begin(server, ns)) && -!(retVal = function_namespace0_generated_186_begin(server, ns)) && -!(retVal = function_namespace0_generated_187_begin(server, ns)) && -!(retVal = function_namespace0_generated_188_begin(server, ns)) && -!(retVal = function_namespace0_generated_189_begin(server, ns)) && -!(retVal = function_namespace0_generated_190_begin(server, ns)) && -!(retVal = function_namespace0_generated_191_begin(server, ns)) && -!(retVal = function_namespace0_generated_192_begin(server, ns)) && -!(retVal = function_namespace0_generated_193_begin(server, ns)) && -!(retVal = function_namespace0_generated_194_begin(server, ns)) && -!(retVal = function_namespace0_generated_195_begin(server, ns)) && -!(retVal = function_namespace0_generated_196_begin(server, ns)) && -!(retVal = function_namespace0_generated_197_begin(server, ns)) && -!(retVal = function_namespace0_generated_198_begin(server, ns)) && -!(retVal = function_namespace0_generated_199_begin(server, ns)) && -!(retVal = function_namespace0_generated_200_begin(server, ns)) && -!(retVal = function_namespace0_generated_201_begin(server, ns)) && -!(retVal = function_namespace0_generated_202_begin(server, ns)) && -!(retVal = function_namespace0_generated_203_begin(server, ns)) && -!(retVal = function_namespace0_generated_204_begin(server, ns)) && -!(retVal = function_namespace0_generated_205_begin(server, ns)) && -!(retVal = function_namespace0_generated_206_begin(server, ns)) && -!(retVal = function_namespace0_generated_207_begin(server, ns)) && -!(retVal = function_namespace0_generated_208_begin(server, ns)) && -!(retVal = function_namespace0_generated_209_begin(server, ns)) && -!(retVal = function_namespace0_generated_210_begin(server, ns)) && -!(retVal = function_namespace0_generated_211_begin(server, ns)) && -!(retVal = function_namespace0_generated_212_begin(server, ns)) && -!(retVal = function_namespace0_generated_213_begin(server, ns)) && -!(retVal = function_namespace0_generated_214_begin(server, ns)) && -!(retVal = function_namespace0_generated_215_begin(server, ns)) && -!(retVal = function_namespace0_generated_216_begin(server, ns)) && -!(retVal = function_namespace0_generated_216_finish(server, ns)) && -!(retVal = function_namespace0_generated_215_finish(server, ns)) && -!(retVal = function_namespace0_generated_214_finish(server, ns)) && -!(retVal = function_namespace0_generated_213_finish(server, ns)) && -!(retVal = function_namespace0_generated_212_finish(server, ns)) && -!(retVal = function_namespace0_generated_211_finish(server, ns)) && -!(retVal = function_namespace0_generated_210_finish(server, ns)) && -!(retVal = function_namespace0_generated_209_finish(server, ns)) && -!(retVal = function_namespace0_generated_208_finish(server, ns)) && -!(retVal = function_namespace0_generated_207_finish(server, ns)) && -!(retVal = function_namespace0_generated_206_finish(server, ns)) && -!(retVal = function_namespace0_generated_205_finish(server, ns)) && -!(retVal = function_namespace0_generated_204_finish(server, ns)) && -!(retVal = function_namespace0_generated_203_finish(server, ns)) && -!(retVal = function_namespace0_generated_202_finish(server, ns)) && -!(retVal = function_namespace0_generated_201_finish(server, ns)) && -!(retVal = function_namespace0_generated_200_finish(server, ns)) && -!(retVal = function_namespace0_generated_199_finish(server, ns)) && -!(retVal = function_namespace0_generated_198_finish(server, ns)) && -!(retVal = function_namespace0_generated_197_finish(server, ns)) && -!(retVal = function_namespace0_generated_196_finish(server, ns)) && -!(retVal = function_namespace0_generated_195_finish(server, ns)) && -!(retVal = function_namespace0_generated_194_finish(server, ns)) && -!(retVal = function_namespace0_generated_193_finish(server, ns)) && -!(retVal = function_namespace0_generated_192_finish(server, ns)) && -!(retVal = function_namespace0_generated_191_finish(server, ns)) && -!(retVal = function_namespace0_generated_190_finish(server, ns)) && -!(retVal = function_namespace0_generated_189_finish(server, ns)) && -!(retVal = function_namespace0_generated_188_finish(server, ns)) && -!(retVal = function_namespace0_generated_187_finish(server, ns)) && -!(retVal = function_namespace0_generated_186_finish(server, ns)) && -!(retVal = function_namespace0_generated_185_finish(server, ns)) && -!(retVal = function_namespace0_generated_184_finish(server, ns)) && -!(retVal = function_namespace0_generated_183_finish(server, ns)) && -!(retVal = function_namespace0_generated_182_finish(server, ns)) && -!(retVal = function_namespace0_generated_181_finish(server, ns)) && -!(retVal = function_namespace0_generated_180_finish(server, ns)) && -!(retVal = function_namespace0_generated_179_finish(server, ns)) && -!(retVal = function_namespace0_generated_178_finish(server, ns)) && -!(retVal = function_namespace0_generated_177_finish(server, ns)) && -!(retVal = function_namespace0_generated_176_finish(server, ns)) && -!(retVal = function_namespace0_generated_175_finish(server, ns)) && -!(retVal = function_namespace0_generated_174_finish(server, ns)) && -!(retVal = function_namespace0_generated_173_finish(server, ns)) && -!(retVal = function_namespace0_generated_172_finish(server, ns)) && -!(retVal = function_namespace0_generated_171_finish(server, ns)) && -!(retVal = function_namespace0_generated_170_finish(server, ns)) && -!(retVal = function_namespace0_generated_169_finish(server, ns)) && -!(retVal = function_namespace0_generated_168_finish(server, ns)) && -!(retVal = function_namespace0_generated_167_finish(server, ns)) && -!(retVal = function_namespace0_generated_166_finish(server, ns)) && -!(retVal = function_namespace0_generated_165_finish(server, ns)) && -!(retVal = function_namespace0_generated_164_finish(server, ns)) && -!(retVal = function_namespace0_generated_163_finish(server, ns)) && -!(retVal = function_namespace0_generated_162_finish(server, ns)) && -!(retVal = function_namespace0_generated_161_finish(server, ns)) && -!(retVal = function_namespace0_generated_160_finish(server, ns)) && -!(retVal = function_namespace0_generated_159_finish(server, ns)) && -!(retVal = function_namespace0_generated_158_finish(server, ns)) && -!(retVal = function_namespace0_generated_157_finish(server, ns)) && -!(retVal = function_namespace0_generated_156_finish(server, ns)) && -!(retVal = function_namespace0_generated_155_finish(server, ns)) && -!(retVal = function_namespace0_generated_154_finish(server, ns)) && -!(retVal = function_namespace0_generated_153_finish(server, ns)) && -!(retVal = function_namespace0_generated_152_finish(server, ns)) && -!(retVal = function_namespace0_generated_151_finish(server, ns)) && -!(retVal = function_namespace0_generated_150_finish(server, ns)) && -!(retVal = function_namespace0_generated_149_finish(server, ns)) && -!(retVal = function_namespace0_generated_148_finish(server, ns)) && -!(retVal = function_namespace0_generated_147_finish(server, ns)) && -!(retVal = function_namespace0_generated_146_finish(server, ns)) && -!(retVal = function_namespace0_generated_145_finish(server, ns)) && -!(retVal = function_namespace0_generated_144_finish(server, ns)) && -!(retVal = function_namespace0_generated_143_finish(server, ns)) && -!(retVal = function_namespace0_generated_142_finish(server, ns)) && -!(retVal = function_namespace0_generated_141_finish(server, ns)) && -!(retVal = function_namespace0_generated_140_finish(server, ns)) && -!(retVal = function_namespace0_generated_139_finish(server, ns)) && -!(retVal = function_namespace0_generated_138_finish(server, ns)) && -!(retVal = function_namespace0_generated_137_finish(server, ns)) && -!(retVal = function_namespace0_generated_136_finish(server, ns)) && -!(retVal = function_namespace0_generated_135_finish(server, ns)) && -!(retVal = function_namespace0_generated_134_finish(server, ns)) && -!(retVal = function_namespace0_generated_133_finish(server, ns)) && -!(retVal = function_namespace0_generated_132_finish(server, ns)) && -!(retVal = function_namespace0_generated_131_finish(server, ns)) && -!(retVal = function_namespace0_generated_130_finish(server, ns)) && -!(retVal = function_namespace0_generated_129_finish(server, ns)) && -!(retVal = function_namespace0_generated_128_finish(server, ns)) && -!(retVal = function_namespace0_generated_127_finish(server, ns)) && -!(retVal = function_namespace0_generated_126_finish(server, ns)) && -!(retVal = function_namespace0_generated_125_finish(server, ns)) && -!(retVal = function_namespace0_generated_124_finish(server, ns)) && -!(retVal = function_namespace0_generated_123_finish(server, ns)) && -!(retVal = function_namespace0_generated_122_finish(server, ns)) && -!(retVal = function_namespace0_generated_121_finish(server, ns)) && -!(retVal = function_namespace0_generated_120_finish(server, ns)) && -!(retVal = function_namespace0_generated_119_finish(server, ns)) && -!(retVal = function_namespace0_generated_118_finish(server, ns)) && -!(retVal = function_namespace0_generated_117_finish(server, ns)) && -!(retVal = function_namespace0_generated_116_finish(server, ns)) && -!(retVal = function_namespace0_generated_115_finish(server, ns)) && -!(retVal = function_namespace0_generated_114_finish(server, ns)) && -!(retVal = function_namespace0_generated_113_finish(server, ns)) && -!(retVal = function_namespace0_generated_112_finish(server, ns)) && -!(retVal = function_namespace0_generated_111_finish(server, ns)) && -!(retVal = function_namespace0_generated_110_finish(server, ns)) && -!(retVal = function_namespace0_generated_109_finish(server, ns)) && -!(retVal = function_namespace0_generated_108_finish(server, ns)) && -!(retVal = function_namespace0_generated_107_finish(server, ns)) && -!(retVal = function_namespace0_generated_106_finish(server, ns)) && -!(retVal = function_namespace0_generated_105_finish(server, ns)) && -!(retVal = function_namespace0_generated_104_finish(server, ns)) && -!(retVal = function_namespace0_generated_103_finish(server, ns)) && -!(retVal = function_namespace0_generated_102_finish(server, ns)) && -!(retVal = function_namespace0_generated_101_finish(server, ns)) && -!(retVal = function_namespace0_generated_100_finish(server, ns)) && -!(retVal = function_namespace0_generated_99_finish(server, ns)) && -!(retVal = function_namespace0_generated_98_finish(server, ns)) && -!(retVal = function_namespace0_generated_97_finish(server, ns)) && -!(retVal = function_namespace0_generated_96_finish(server, ns)) && -!(retVal = function_namespace0_generated_95_finish(server, ns)) && -!(retVal = function_namespace0_generated_94_finish(server, ns)) && -!(retVal = function_namespace0_generated_93_finish(server, ns)) && -!(retVal = function_namespace0_generated_92_finish(server, ns)) && -!(retVal = function_namespace0_generated_91_finish(server, ns)) && -!(retVal = function_namespace0_generated_90_finish(server, ns)) && -!(retVal = function_namespace0_generated_89_finish(server, ns)) && -!(retVal = function_namespace0_generated_88_finish(server, ns)) && -!(retVal = function_namespace0_generated_87_finish(server, ns)) && -!(retVal = function_namespace0_generated_86_finish(server, ns)) && -!(retVal = function_namespace0_generated_85_finish(server, ns)) && -!(retVal = function_namespace0_generated_84_finish(server, ns)) && -!(retVal = function_namespace0_generated_83_finish(server, ns)) && -!(retVal = function_namespace0_generated_82_finish(server, ns)) && -!(retVal = function_namespace0_generated_81_finish(server, ns)) && -!(retVal = function_namespace0_generated_80_finish(server, ns)) && -!(retVal = function_namespace0_generated_79_finish(server, ns)) && -!(retVal = function_namespace0_generated_78_finish(server, ns)) && -!(retVal = function_namespace0_generated_77_finish(server, ns)) && -!(retVal = function_namespace0_generated_76_finish(server, ns)) && -!(retVal = function_namespace0_generated_75_finish(server, ns)) && -!(retVal = function_namespace0_generated_74_finish(server, ns)) && -!(retVal = function_namespace0_generated_73_finish(server, ns)) && -!(retVal = function_namespace0_generated_72_finish(server, ns)) && -!(retVal = function_namespace0_generated_71_finish(server, ns)) && -!(retVal = function_namespace0_generated_70_finish(server, ns)) && -!(retVal = function_namespace0_generated_69_finish(server, ns)) && -!(retVal = function_namespace0_generated_68_finish(server, ns)) && -!(retVal = function_namespace0_generated_67_finish(server, ns)) && -!(retVal = function_namespace0_generated_66_finish(server, ns)) && -!(retVal = function_namespace0_generated_65_finish(server, ns)) && -!(retVal = function_namespace0_generated_64_finish(server, ns)) && -!(retVal = function_namespace0_generated_63_finish(server, ns)) && -!(retVal = function_namespace0_generated_62_finish(server, ns)) && -!(retVal = function_namespace0_generated_61_finish(server, ns)) && -!(retVal = function_namespace0_generated_60_finish(server, ns)) && -!(retVal = function_namespace0_generated_59_finish(server, ns)) && -!(retVal = function_namespace0_generated_58_finish(server, ns)) && -!(retVal = function_namespace0_generated_57_finish(server, ns)) && -!(retVal = function_namespace0_generated_56_finish(server, ns)) && -!(retVal = function_namespace0_generated_55_finish(server, ns)) && -!(retVal = function_namespace0_generated_54_finish(server, ns)) && -!(retVal = function_namespace0_generated_53_finish(server, ns)) && -!(retVal = function_namespace0_generated_52_finish(server, ns)) && -!(retVal = function_namespace0_generated_51_finish(server, ns)) && -!(retVal = function_namespace0_generated_50_finish(server, ns)) && -!(retVal = function_namespace0_generated_49_finish(server, ns)) && -!(retVal = function_namespace0_generated_48_finish(server, ns)) && -!(retVal = function_namespace0_generated_47_finish(server, ns)) && -!(retVal = function_namespace0_generated_46_finish(server, ns)) && -!(retVal = function_namespace0_generated_45_finish(server, ns)) && -!(retVal = function_namespace0_generated_44_finish(server, ns)) && -!(retVal = function_namespace0_generated_43_finish(server, ns)) && -!(retVal = function_namespace0_generated_42_finish(server, ns)) && -!(retVal = function_namespace0_generated_41_finish(server, ns)) && -!(retVal = function_namespace0_generated_40_finish(server, ns)) && -!(retVal = function_namespace0_generated_39_finish(server, ns)) && -!(retVal = function_namespace0_generated_38_finish(server, ns)) && -!(retVal = function_namespace0_generated_37_finish(server, ns)) && -!(retVal = function_namespace0_generated_36_finish(server, ns)) && -!(retVal = function_namespace0_generated_35_finish(server, ns)) && -!(retVal = function_namespace0_generated_34_finish(server, ns)) && -!(retVal = function_namespace0_generated_33_finish(server, ns)) && -!(retVal = function_namespace0_generated_32_finish(server, ns)) && -!(retVal = function_namespace0_generated_31_finish(server, ns)) && -!(retVal = function_namespace0_generated_30_finish(server, ns)) && -!(retVal = function_namespace0_generated_29_finish(server, ns)) && -!(retVal = function_namespace0_generated_28_finish(server, ns)) && -!(retVal = function_namespace0_generated_27_finish(server, ns)) && -!(retVal = function_namespace0_generated_26_finish(server, ns)) && -!(retVal = function_namespace0_generated_25_finish(server, ns)) && -!(retVal = function_namespace0_generated_24_finish(server, ns)) && -!(retVal = function_namespace0_generated_23_finish(server, ns)) && -!(retVal = function_namespace0_generated_22_finish(server, ns)) && -!(retVal = function_namespace0_generated_21_finish(server, ns)) && -!(retVal = function_namespace0_generated_20_finish(server, ns)) && -!(retVal = function_namespace0_generated_19_finish(server, ns)) && -!(retVal = function_namespace0_generated_18_finish(server, ns)) && -!(retVal = function_namespace0_generated_17_finish(server, ns)) && -!(retVal = function_namespace0_generated_16_finish(server, ns)) && -!(retVal = function_namespace0_generated_15_finish(server, ns)) && -!(retVal = function_namespace0_generated_14_finish(server, ns)) && -!(retVal = function_namespace0_generated_13_finish(server, ns)) && -!(retVal = function_namespace0_generated_12_finish(server, ns)) && -!(retVal = function_namespace0_generated_11_finish(server, ns)) && -!(retVal = function_namespace0_generated_10_finish(server, ns)) && -!(retVal = function_namespace0_generated_9_finish(server, ns)) && -!(retVal = function_namespace0_generated_8_finish(server, ns)) && -!(retVal = function_namespace0_generated_7_finish(server, ns)) && -!(retVal = function_namespace0_generated_6_finish(server, ns)) && -!(retVal = function_namespace0_generated_5_finish(server, ns)) && -!(retVal = function_namespace0_generated_4_finish(server, ns)) && -!(retVal = function_namespace0_generated_3_finish(server, ns)) && -!(retVal = function_namespace0_generated_2_finish(server, ns)) && -!(retVal = function_namespace0_generated_1_finish(server, ns)) && -!(retVal = function_namespace0_generated_0_finish(server, ns)) -); (void)(dummy); + +/* Load custom datatype definitions into the server */ +if((retVal = function_namespace0_generated_0_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_0_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_1_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_1_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_2_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_2_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_3_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_3_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_4_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_4_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_5_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_5_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_6_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_7_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_8_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_9_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_10_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_11_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_12_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_13_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_14_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_15_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_16_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_17_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_18_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_19_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_20_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_21_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_22_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_23_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_24_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_25_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_26_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_27_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_28_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_29_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_30_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_31_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_32_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_33_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_34_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_35_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_36_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_37_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_38_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_39_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_40_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_41_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_42_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_43_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_44_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_45_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_46_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_47_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_48_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_49_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_50_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_51_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_52_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_53_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_54_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_55_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_56_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_57_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_58_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_59_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_60_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_61_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_62_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_63_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_64_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_65_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_66_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_67_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_68_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_69_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_70_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_71_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_72_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_73_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_74_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_75_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_76_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_77_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_78_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_79_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_80_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_81_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_82_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_83_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_84_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_85_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_86_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_87_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_88_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_89_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_90_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_91_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_92_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_93_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_94_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_95_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_96_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_97_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_98_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_99_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_100_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_101_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_102_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_103_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_104_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_105_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_106_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_107_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_108_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_109_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_110_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_111_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_112_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_113_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_114_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_115_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_116_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_117_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_118_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_119_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_120_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_121_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_122_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_123_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_124_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_125_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_126_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_127_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_128_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_129_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_130_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_131_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_132_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_133_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_134_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_135_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_136_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_137_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_138_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_139_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_140_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_141_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_142_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_143_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_144_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_145_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_146_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_147_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_148_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_149_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_150_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_151_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_152_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_153_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_154_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_155_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_156_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_157_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_158_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_159_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_160_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_161_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_162_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_163_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_164_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_165_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_166_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_167_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_168_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_169_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_170_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_171_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_172_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_173_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_174_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_175_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_176_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_177_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_178_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_179_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_180_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_181_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_182_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_183_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_184_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_185_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_186_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_187_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_188_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_189_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_190_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_191_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_192_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_193_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_194_begin(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_194_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_193_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_192_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_191_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_190_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_189_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_188_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_187_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_186_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_185_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_184_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_183_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_182_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_181_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_180_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_179_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_178_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_177_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_176_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_175_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_174_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_173_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_172_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_171_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_170_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_169_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_168_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_167_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_166_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_165_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_164_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_163_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_162_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_161_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_160_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_159_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_158_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_157_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_156_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_155_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_154_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_153_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_152_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_151_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_150_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_149_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_148_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_147_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_146_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_145_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_144_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_143_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_142_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_141_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_140_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_139_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_138_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_137_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_136_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_135_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_134_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_133_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_132_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_131_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_130_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_129_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_128_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_127_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_126_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_125_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_124_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_123_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_122_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_121_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_120_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_119_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_118_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_117_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_116_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_115_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_114_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_113_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_112_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_111_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_110_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_109_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_108_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_107_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_106_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_105_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_104_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_103_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_102_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_101_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_100_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_99_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_98_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_97_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_96_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_95_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_94_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_93_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_92_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_91_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_90_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_89_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_88_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_87_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_86_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_85_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_84_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_83_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_82_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_81_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_80_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_79_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_78_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_77_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_76_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_75_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_74_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_73_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_72_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_71_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_70_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_69_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_68_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_67_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_66_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_65_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_64_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_63_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_62_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_61_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_60_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_59_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_58_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_57_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_56_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_55_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_54_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_53_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_52_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_51_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_50_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_49_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_48_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_47_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_46_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_45_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_44_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_43_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_42_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_41_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_40_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_39_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_38_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_37_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_36_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_35_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_34_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_33_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_32_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_31_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_30_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_29_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_28_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_27_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_26_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_25_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_24_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_23_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_22_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_21_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_20_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_19_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_18_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_17_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_16_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_15_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_14_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_13_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_12_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_11_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_10_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_9_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_8_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_7_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; +if((retVal = function_namespace0_generated_6_finish(server, ns)) != UA_STATUSCODE_GOOD) return retVal; return retVal; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/ua_types_lex.c" ***********************************/ +/**** amalgamated original file "/src/ua_types_lex.c" ****/ /* Generated by re2c 1.1.1 */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * @@ -52602,7 +57670,7 @@ parse_nodeid(UA_NodeId *id, const char *pos, const char *end) { memset(&context, 0, sizeof(LexContext)); const char *ns = NULL, *nse= NULL; - + { char yych; yych = YYPEEK (); @@ -52737,7 +57805,7 @@ parse_expandednodeid(UA_ExpandedNodeId *id, const char *pos, const char *end) { memset(&context, 0, sizeof(LexContext)); const char *svr = NULL, *svre = NULL, *nsu = NULL, *ns = NULL, *body = NULL; - + { char yych; yych = YYPEEK (); @@ -53040,7 +58108,7 @@ parse_refpath_qn_name(UA_QualifiedName *qn, const char **pos, const char *end) { size_t maxlen = (size_t)(end - *pos); if(maxlen == 0) { qn->name.data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL; - return UA_STATUSCODE_GOOD;; + return UA_STATUSCODE_GOOD; } char *name = (char*)UA_malloc(maxlen); if(!name) @@ -53088,7 +58156,7 @@ parse_refpath_qn(UA_QualifiedName *qn, const char *pos, const char *end) { const char *ns = NULL, *nse = NULL; UA_QualifiedName_init(qn); - + { char yych; yych = YYPEEK (); @@ -53230,7 +58298,7 @@ parse_relativepath(UA_RelativePath *rp, const char *pos, const char *end) { current.includeSubtypes = true; /* Follow subtypes by default */ /* Get the ReferenceType and its modifiers */ - + { char yych; unsigned int yyaccept = 0; @@ -53346,7 +58414,7 @@ yy71: if(res != UA_STATUSCODE_GOOD) return res; - + { char yych; yych = YYPEEK (); @@ -53412,7 +58480,7 @@ UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str) { return res; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_subscription.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_subscription.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -53436,45 +58504,82 @@ UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str) { #ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ +#define UA_MAX_RETRANSMISSIONQUEUESIZE 256 + UA_Subscription * -UA_Subscription_new(UA_Session *session, UA_UInt32 subscriptionId) { +UA_Subscription_new(void) { /* Allocate the memory */ - UA_Subscription *newSub = - (UA_Subscription*)UA_calloc(1, sizeof(UA_Subscription)); + UA_Subscription *newSub = (UA_Subscription*)UA_calloc(1, sizeof(UA_Subscription)); if(!newSub) return NULL; - /* Remaining members are covered by calloc zeroing out the memory */ - newSub->session = session; - newSub->subscriptionId = subscriptionId; - newSub->state = UA_SUBSCRIPTIONSTATE_NORMAL; /* The first publish response is sent immediately */ + /* The first publish response is sent immediately */ + newSub->state = UA_SUBSCRIPTIONSTATE_NORMAL; + /* Even if the first publish response is a keepalive the sequence number is 1. * This can happen by a subscription without a monitored item (see CTT test scripts). */ newSub->nextSequenceNumber = 1; + TAILQ_INIT(&newSub->retransmissionQueue); TAILQ_INIT(&newSub->notificationQueue); return newSub; } void -UA_Subscription_deleteMembers(UA_Server *server, UA_Subscription *sub) { - UA_LOCK_ASSERT(server->serviceMutex, 1); +UA_Subscription_delete(UA_Server *server, UA_Subscription *sub) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + /* Unregister the publish callback */ Subscription_unregisterPublishCallback(server, sub); + /* Remove the diagnostics object for the subscription */ +#ifdef UA_ENABLE_DIAGNOSTICS + if(sub->session) { + /* Use a browse path to find the node */ + char subIdStr[32]; + snprintf(subIdStr, 32, "%u", sub->subscriptionId); + UA_BrowsePath bp; + UA_BrowsePath_init(&bp); + bp.startingNode = sub->session->sessionId; + UA_RelativePathElement rpe[2]; + memset(rpe, 0, sizeof(UA_RelativePathElement) * 2); + rpe[0].targetName = UA_QUALIFIEDNAME(0, "SubscriptionDiagnosticsArray"); + rpe[1].targetName = UA_QUALIFIEDNAME(0, subIdStr); + bp.relativePath.elements = rpe; + bp.relativePath.elementsSize = 2; + UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp); + + /* Delete all nodes matching the browse path */ + for(size_t i = 0; i < bpr.targetsSize; i++) { + if(bpr.targets[i].remainingPathIndex < UA_UINT32_MAX) + continue; + deleteNode(server, bpr.targets[i].targetId.nodeId, true); + } + UA_BrowsePathResult_clear(&bpr); + } +#endif + + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, sub, "Subscription deleted"); + + /* Detach from the session if necessary */ + if(sub->session) + UA_Session_detachSubscription(server, sub->session, sub, true); + + /* Remove from the server if not previously registered */ + if(sub->serverListEntry.le_prev) { + LIST_REMOVE(sub, serverListEntry); + UA_assert(server->subscriptionsSize > 0); + server->subscriptionsSize--; + server->serverDiagnosticsSummary.currentSubscriptionCount--; + } + /* Delete monitored Items */ + UA_assert(server->monitoredItemsSize >= sub->monitoredItemsSize); UA_MonitoredItem *mon, *tmp_mon; LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, tmp_mon) { - LIST_REMOVE(mon, listEntry); - UA_LOG_INFO_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | MonitoredItem %" PRIi32 " | " - "Deleted the MonitoredItem", sub->subscriptionId, - mon->monitoredItemId); UA_MonitoredItem_delete(server, mon); } - UA_assert(server->numMonitoredItems >= sub->monitoredItemsSize); - server->numMonitoredItems -= sub->monitoredItemsSize; - sub->monitoredItemsSize = 0; + UA_assert(sub->monitoredItemsSize == 0); /* Delete Retransmission Queue */ UA_NotificationMessageEntry *nme, *nme_tmp; @@ -53482,14 +58587,21 @@ UA_Subscription_deleteMembers(UA_Server *server, UA_Subscription *sub) { TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry); UA_NotificationMessage_clear(&nme->message); UA_free(nme); - --sub->session->totalRetransmissionQueueSize; + if(sub->session) + --sub->session->totalRetransmissionQueueSize; --sub->retransmissionQueueSize; } UA_assert(sub->retransmissionQueueSize == 0); - UA_LOG_INFO_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Deleted the Subscription", - sub->subscriptionId); + /* Add a delayed callback to remove the Subscription when the current jobs + * have completed. Pointers to the subscription may still exist upwards in + * the call stack. */ + sub->delayedFreePointers.callback = NULL; + sub->delayedFreePointers.application = server; + sub->delayedFreePointers.data = NULL; + sub->delayedFreePointers.nextTime = UA_DateTime_nowMonotonic() + 1; + sub->delayedFreePointers.interval = 0; /* Remove the structure */ + UA_Timer_addTimerEntry(&server->timer, &sub->delayedFreePointers, NULL); } UA_MonitoredItem * @@ -53502,54 +58614,30 @@ UA_Subscription_getMonitoredItem(UA_Subscription *sub, UA_UInt32 monitoredItemId return mon; } -UA_StatusCode -UA_Subscription_deleteMonitoredItem(UA_Server *server, UA_Subscription *sub, - UA_UInt32 monitoredItemId) { - UA_LOCK_ASSERT(server->serviceMutex, 1); - - /* Find the MonitoredItem */ - UA_MonitoredItem *mon; - LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { - if(mon->monitoredItemId == monitoredItemId) - break; - } - if(!mon) - return UA_STATUSCODE_BADMONITOREDITEMIDINVALID; - - UA_LOG_INFO_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | MonitoredItem %" PRIi32 " | " - "Delete the MonitoredItem", sub->subscriptionId, - mon->monitoredItemId); - - /* Remove the MonitoredItem */ - LIST_REMOVE(mon, listEntry); - UA_assert(sub->monitoredItemsSize > 0); - UA_assert(server->numMonitoredItems > 0); - sub->monitoredItemsSize--; - server->numMonitoredItems--; - - /* Remove content and delayed free */ - UA_MonitoredItem_delete(server, mon); - - return UA_STATUSCODE_GOOD; -} +static void +removeOldestRetransmissionMessageFromSub(UA_Subscription *sub) { + UA_NotificationMessageEntry *oldestEntry = + TAILQ_LAST(&sub->retransmissionQueue, NotificationMessageQueue); + TAILQ_REMOVE(&sub->retransmissionQueue, oldestEntry, listEntry); + UA_NotificationMessage_clear(&oldestEntry->message); + UA_free(oldestEntry); + --sub->retransmissionQueueSize; + if(sub->session) + --sub->session->totalRetransmissionQueueSize; -void -UA_Subscription_addMonitoredItem(UA_Server *server, UA_Subscription *sub, UA_MonitoredItem *newMon) { - sub->monitoredItemsSize++; - server->numMonitoredItems++; - LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry); +#ifdef UA_ENABLE_DIAGNOSTICS + sub->discardedMessageCount++; +#endif } static void -removeOldestRetransmissionMessage(UA_Session *session) { +removeOldestRetransmissionMessageFromSession(UA_Session *session) { UA_NotificationMessageEntry *oldestEntry = NULL; UA_Subscription *oldestSub = NULL; - UA_Subscription *sub; - LIST_FOREACH(sub, &session->serverSubscriptions, listEntry) { + TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) { UA_NotificationMessageEntry *first = - TAILQ_LAST(&sub->retransmissionQueue, ListOfNotificationMessages); + TAILQ_LAST(&sub->retransmissionQueue, NotificationMessageQueue); if(!first) continue; if(!oldestEntry || oldestEntry->message.publishTime > first->message.publishTime) { @@ -53560,28 +58648,31 @@ removeOldestRetransmissionMessage(UA_Session *session) { UA_assert(oldestEntry); UA_assert(oldestSub); - TAILQ_REMOVE(&oldestSub->retransmissionQueue, oldestEntry, listEntry); - UA_NotificationMessage_clear(&oldestEntry->message); - UA_free(oldestEntry); - --session->totalRetransmissionQueueSize; - --oldestSub->retransmissionQueueSize; + removeOldestRetransmissionMessageFromSub(oldestSub); } static void UA_Subscription_addRetransmissionMessage(UA_Server *server, UA_Subscription *sub, UA_NotificationMessageEntry *entry) { /* Release the oldest entry if there is not enough space */ - if(server->config.maxRetransmissionQueueSize > 0 && - sub->session->totalRetransmissionQueueSize >= server->config.maxRetransmissionQueueSize) { - UA_LOG_WARNING_SESSION(&server->config.logger, sub->session, "Subscription %" PRIu32 " | " - "Retransmission queue overflow", sub->subscriptionId); - removeOldestRetransmissionMessage(sub->session); + UA_Session *session = sub->session; + if(sub->retransmissionQueueSize >= UA_MAX_RETRANSMISSIONQUEUESIZE) { + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "Subscription retransmission queue overflow"); + removeOldestRetransmissionMessageFromSub(sub); + } else if(session && server->config.maxRetransmissionQueueSize > 0 && + session->totalRetransmissionQueueSize >= + server->config.maxRetransmissionQueueSize) { + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "Session-wide retransmission queue overflow"); + removeOldestRetransmissionMessageFromSession(sub->session); } /* Add entry */ TAILQ_INSERT_TAIL(&sub->retransmissionQueue, entry, listEntry); - ++sub->session->totalRetransmissionQueueSize; ++sub->retransmissionQueueSize; + if(session) + ++session->totalRetransmissionQueueSize; } UA_StatusCode @@ -53597,19 +58688,29 @@ UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub, UA_UInt32 sequ /* Remove the retransmission message */ TAILQ_REMOVE(&sub->retransmissionQueue, entry, listEntry); - --sub->session->totalRetransmissionQueueSize; --sub->retransmissionQueueSize; UA_NotificationMessage_clear(&entry->message); UA_free(entry); + + if(sub->session) + --sub->session->totalRetransmissionQueueSize; + return UA_STATUSCODE_GOOD; } +/* The output counters are only set when the preparation is successful */ static UA_StatusCode prepareNotificationMessage(UA_Server *server, UA_Subscription *sub, - UA_NotificationMessage *message, size_t notifications) { - UA_assert(notifications > 0); + UA_NotificationMessage *message, + size_t maxNotifications) { + UA_assert(maxNotifications > 0); - /* Allocate an ExtensionObject for events and data */ + /* Allocate an ExtensionObject for Event- and DataChange-Notifications. Also + * there can be StatusChange-Notifications. The standard says in Part 4, + * 7.2.1: + * + * If a Subscription contains MonitoredItems for events and data, this array + * should have not more than 2 elements. */ message->notificationData = (UA_ExtensionObject*) UA_Array_new(2, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); if(!message->notificationData) @@ -53618,6 +58719,7 @@ prepareNotificationMessage(UA_Server *server, UA_Subscription *sub, /* Pre-allocate DataChangeNotifications */ size_t notificationDataIdx = 0; + size_t dcnPos = 0; /* How many DataChangeNotifications? */ UA_DataChangeNotification *dcn = NULL; if(sub->dataChangeNotifications > 0) { dcn = UA_DataChangeNotification_new(); @@ -53625,13 +58727,11 @@ prepareNotificationMessage(UA_Server *server, UA_Subscription *sub, UA_NotificationMessage_clear(message); return UA_STATUSCODE_BADOUTOFMEMORY; } - message->notificationData->encoding = UA_EXTENSIONOBJECT_DECODED; - message->notificationData->content.decoded.data = dcn; - message->notificationData->content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]; - + UA_ExtensionObject_setValue(message->notificationData, dcn, + &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]); size_t dcnSize = sub->dataChangeNotifications; - if(dcnSize > notifications) - dcnSize = notifications; + if(dcnSize > maxNotifications) + dcnSize = maxNotifications; dcn->monitoredItems = (UA_MonitoredItemNotification*) UA_Array_new(dcnSize, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]); if(!dcn->monitoredItems) { @@ -53643,34 +58743,21 @@ prepareNotificationMessage(UA_Server *server, UA_Subscription *sub, } #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + size_t enlPos = 0; /* How many EventNotifications? */ UA_EventNotificationList *enl = NULL; - UA_StatusChangeNotification *scn = NULL; - /* Pre-allocate either StatusChange or EventNotifications. Sending a - * (single) StatusChangeNotification has priority. */ - if(sub->statusChangeNotifications > 0) { - scn = UA_StatusChangeNotification_new(); - if(!scn) { - UA_NotificationMessage_clear(message); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - message->notificationData[notificationDataIdx].encoding = UA_EXTENSIONOBJECT_DECODED; - message->notificationData[notificationDataIdx].content.decoded.data = scn; - message->notificationData[notificationDataIdx].content.decoded.type = &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]; - notificationDataIdx++; - } else if(sub->eventNotifications > 0) { + if(sub->eventNotifications > 0) { enl = UA_EventNotificationList_new(); if(!enl) { UA_NotificationMessage_clear(message); return UA_STATUSCODE_BADOUTOFMEMORY; } - message->notificationData[notificationDataIdx].encoding = UA_EXTENSIONOBJECT_DECODED; - message->notificationData[notificationDataIdx].content.decoded.data = enl; - message->notificationData[notificationDataIdx].content.decoded.type = &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]; - + UA_ExtensionObject_setValue(&message->notificationData[notificationDataIdx], + enl, &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]); size_t enlSize = sub->eventNotifications; - if(enlSize > notifications) - enlSize = notifications; - enl->events = (UA_EventFieldList*) UA_Array_new(enlSize, &UA_TYPES[UA_TYPES_EVENTFIELDLIST]); + if(enlSize > maxNotifications) + enlSize = maxNotifications; + enl->events = (UA_EventFieldList*) + UA_Array_new(enlSize, &UA_TYPES[UA_TYPES_EVENTFIELDLIST]); if(!enl->events) { UA_NotificationMessage_clear(message); return UA_STATUSCODE_BADOUTOFMEMORY; @@ -53685,47 +58772,44 @@ prepareNotificationMessage(UA_Server *server, UA_Subscription *sub, /* <-- The point of no return --> */ - size_t totalNotifications = 0; /* How many notifications were moved to the response overall? */ - size_t dcnPos = 0; /* How many DataChangeNotifications were put into the list? */ -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - size_t enlPos = 0; /* How many EventNotifications were moved into the list */ -#endif + /* How many notifications were moved to the response overall? */ + size_t totalNotifications = 0; UA_Notification *notification, *notification_tmp; - TAILQ_FOREACH_SAFE(notification, &sub->notificationQueue, globalEntry, notification_tmp) { - if(totalNotifications >= notifications) + TAILQ_FOREACH_SAFE(notification, &sub->notificationQueue, + globalEntry, notification_tmp) { + if(totalNotifications >= maxNotifications) break; - UA_MonitoredItem *mon = notification->mon; - - /* Remove from the queues and decrease the counters */ - UA_Notification_dequeue(server, notification); - /* Move the content to the response */ + switch(notification->mon->itemToMonitor.attributeId) { #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - + case UA_ATTRIBUTEID_EVENTNOTIFIER: UA_assert(enl != NULL); /* Have at least one event notification */ - - /* Move the content to the response */ - UA_EventFieldList *efl = &enl->events[enlPos]; - *efl = notification->data.event.fields; - UA_EventFieldList_init(¬ification->data.event.fields); - efl->clientHandle = mon->clientHandle; - + enl->events[enlPos] = notification->data.event; + UA_EventFieldList_init(¬ification->data.event); enlPos++; - } else + break; #endif - { + default: UA_assert(dcn != NULL); /* Have at least one change notification */ - /* Move the content to the response */ - UA_MonitoredItemNotification *min = &dcn->monitoredItems[dcnPos]; - min->clientHandle = mon->clientHandle; - min->value = notification->data.value; - UA_DataValue_init(¬ification->data.value); /* Reset after the value has been moved */ + dcn->monitoredItems[dcnPos] = notification->data.dataChange; + UA_DataValue_init(¬ification->data.dataChange.value); dcnPos++; + break; + } + + /* If there are Notifications *before this one* in the MonitoredItem- + * local queue, remove all of them. These are earlier Notifications that + * are non-reporting. And we don't want them to show up after the + * current Notification has been sent out. */ + UA_Notification *prev; + while((prev = TAILQ_PREV(notification, NotificationQueue, localEntry))) { + UA_Notification_delete(prev); } + /* Delete the notification, remove from the queues and decrease the counters */ UA_Notification_delete(notification); + totalNotifications++; } @@ -53763,52 +58847,109 @@ UA_Subscription_nextSequenceNumber(UA_UInt32 sequenceNumber) { static void publishCallback(UA_Server *server, UA_Subscription *sub) { - sub->readyNotifications = sub->notificationQueueSize; - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); UA_Subscription_publish(server, sub); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); +} + +static void +sendStatusChangeDelete(UA_Server *server, UA_Subscription *sub, + UA_PublishResponseEntry *pre) { + /* Cannot send out the StatusChange because no response is queued. + * Delete the Subscription without sending the StatusChange. */ + if(!pre) { + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Cannot send the StatusChange notification. " + "Removing the subscription."); + UA_Subscription_delete(server, sub); + return; + } + + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Sending out a StatusChange " + "notification and removing the subscription"); + + /* Populate the response */ + UA_PublishResponse *response = &pre->response; + + UA_StatusChangeNotification scn; + UA_StatusChangeNotification_init(&scn); + scn.status = sub->statusChange; + + UA_ExtensionObject notificationData; + UA_ExtensionObject_setValue(¬ificationData, &scn, + &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]); + + response->responseHeader.timestamp = UA_DateTime_now(); + response->notificationMessage.notificationData = ¬ificationData; + response->notificationMessage.notificationDataSize = 1; + response->subscriptionId = sub->subscriptionId; + response->notificationMessage.publishTime = response->responseHeader.timestamp; + response->notificationMessage.sequenceNumber = sub->nextSequenceNumber; + + /* Send the response */ + UA_assert(sub->session); /* Otherwise pre is NULL */ + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Sending out a publish response"); + sendResponse(server, sub->session, sub->session->header.channel, pre->requestId, + (UA_Response *)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + + /* Clean up */ + response->notificationMessage.notificationData = NULL; + response->notificationMessage.notificationDataSize = 0; + UA_PublishResponse_clear(&pre->response); + UA_free(pre); + + /* Delete the subscription */ + UA_Subscription_delete(server, sub); +} + +/* Called every time we set the subscription late (or it is still late) */ +static void +UA_Subscription_isLate(UA_Subscription *sub) { + sub->state = UA_SUBSCRIPTIONSTATE_LATE; +#ifdef UA_ENABLE_DIAGNOSTICS + sub->latePublishRequestCount++; +#endif } void UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, "Publish Callback"); + UA_assert(sub); - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, "Subscription %" PRIu32 " | " - "Publish Callback", sub->subscriptionId); /* Dequeue a response */ - UA_PublishResponseEntry *pre = UA_Session_dequeuePublishReq(sub->session); + UA_PublishResponseEntry *pre = NULL; + if(sub->session) + pre = UA_Session_dequeuePublishReq(sub->session); + + /* Update the LifetimeCounter */ if(pre) { - sub->currentLifetimeCount = 0; /* Reset the LifetimeCounter */ + sub->currentLifetimeCount = 0; } else { - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | The publish queue is empty", - sub->subscriptionId); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "The publish queue is empty"); ++sub->currentLifetimeCount; - if(sub->currentLifetimeCount > sub->lifeTimeCount) { - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | End of lifetime " - "for subscription", sub->subscriptionId); - UA_Session_deleteSubscription(server, sub->session, sub->subscriptionId); - /* TODO: send a StatusChangeNotification with Bad_Timeout */ - return; + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "End of subscription lifetime"); + /* Set the StatusChange to delete the subscription. */ + sub->statusChange = UA_STATUSCODE_BADTIMEOUT; } } - /* If there are several late publish responses... */ - if(sub->readyNotifications > sub->notificationQueueSize) - sub->readyNotifications = sub->notificationQueueSize; + /* Send a StatusChange notification if possible and delete the + * Subscription */ + if(sub->statusChange != UA_STATUSCODE_GOOD) { + sendStatusChangeDelete(server, sub, pre); + return; + } /* Count the available notifications */ - UA_UInt32 notifications = sub->readyNotifications; - if(!sub->publishingEnabled) - notifications = 0; - - UA_Boolean moreNotifications = false; - if(notifications > sub->notificationsPerPublish) { + UA_UInt32 notifications = (sub->publishingEnabled) ? sub->notificationQueueSize : 0; + if(notifications > sub->notificationsPerPublish) notifications = sub->notificationsPerPublish; - moreNotifications = true; - } /* Return if no notifications and no keepalive */ if(notifications == 0) { @@ -53818,51 +58959,60 @@ UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) { UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ return; } - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Sending a KeepAlive", - sub->subscriptionId); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, "Sending a KeepAlive"); } - /* We want to send a response. Is the channel open? */ - UA_SecureChannel *channel = sub->session->header.channel; - if(!channel || !pre) { - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Want to send a publish response but can't. " - "The subscription is late.", sub->subscriptionId); - sub->state = UA_SUBSCRIPTIONSTATE_LATE; + /* We want to send a response, but cannot. Either because there is no queued + * response or because the Subscription is detached from a Session or because + * the SecureChannel for the Session is closed. */ + if(!pre || !sub->session || !sub->session->header.channel) { + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Want to send a publish response but cannot. " + "The subscription is late."); + UA_Subscription_isLate(sub); if(pre) UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ return; } + UA_assert(pre); + UA_assert(sub->session); /* Otherwise pre is NULL */ + /* Prepare the response */ UA_PublishResponse *response = &pre->response; UA_NotificationMessage *message = &response->notificationMessage; UA_NotificationMessageEntry *retransmission = NULL; +#ifdef UA_ENABLE_DIAGNOSTICS + size_t priorDataChangeNotifications = sub->dataChangeNotifications; + size_t priorEventNotifications = sub->eventNotifications; +#endif if(notifications > 0) { if(server->config.enableRetransmissionQueue) { /* Allocate the retransmission entry */ - retransmission = (UA_NotificationMessageEntry*)UA_malloc(sizeof(UA_NotificationMessageEntry)); + retransmission = (UA_NotificationMessageEntry*) + UA_malloc(sizeof(UA_NotificationMessageEntry)); if(!retransmission) { - UA_LOG_WARNING_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Could not allocate memory for retransmission. " - "The subscription is late.", sub->subscriptionId); - sub->state = UA_SUBSCRIPTIONSTATE_LATE; + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "Could not allocate memory for retransmission. " + "The subscription is late."); + + UA_Subscription_isLate(sub); UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ return; } } /* Prepare the response */ - UA_StatusCode retval = prepareNotificationMessage(server, sub, message, notifications); + UA_StatusCode retval = + prepareNotificationMessage(server, sub, message, notifications); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Could not prepare the notification message. " - "The subscription is late.", sub->subscriptionId); + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "Could not prepare the notification message. " + "The subscription is late."); /* If the retransmission queue is enabled a retransmission message is allocated */ if(retransmission) UA_free(retransmission); - sub->state = UA_SUBSCRIPTIONSTATE_LATE; + UA_Subscription_isLate(sub); UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ return; } @@ -53870,9 +59020,8 @@ UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) { /* <-- The point of no return --> */ - /* Adjust the number of ready notifications */ - UA_assert(sub->readyNotifications >= notifications); - sub->readyNotifications -= notifications; + /* Notifications remaining? */ + UA_Boolean moreNotifications = (sub->notificationQueueSize > 0); /* Set up the response */ response->responseHeader.timestamp = UA_DateTime_now(); @@ -53880,44 +59029,44 @@ UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) { response->moreNotifications = moreNotifications; message->publishTime = response->responseHeader.timestamp; - /* Set sequence number to message. Started at 1 which is given - * during creating a new subscription. The 1 is required for - * initial publish response with or without an monitored item. */ + /* Set sequence number to message. Started at 1 which is given during + * creating a new subscription. The 1 is required for initial publish + * response with or without an monitored item. */ message->sequenceNumber = sub->nextSequenceNumber; if(notifications > 0) { - /* If the retransmission queue is enabled a retransmission message is allocated */ + /* If the retransmission queue is enabled a retransmission message is + * allocated */ if(retransmission) { /* Put the notification message into the retransmission queue. This - * needs to be done here, so that the message itself is included in the - * available sequence numbers for acknowledgement. */ + * needs to be done here, so that the message itself is included in + * the available sequence numbers for acknowledgement. */ retransmission->message = response->notificationMessage; UA_Subscription_addRetransmissionMessage(server, sub, retransmission); } - /* Only if a notification was created, the sequence number must be increased. - * For a keepalive the sequence number can be reused. */ - sub->nextSequenceNumber = UA_Subscription_nextSequenceNumber(sub->nextSequenceNumber); + /* Only if a notification was created, the sequence number must be + * increased. For a keepalive the sequence number can be reused. */ + sub->nextSequenceNumber = + UA_Subscription_nextSequenceNumber(sub->nextSequenceNumber); } /* Get the available sequence numbers from the retransmission queue */ - size_t available = sub->retransmissionQueueSize; - UA_STACKARRAY(UA_UInt32, seqNumbers, available); - if(available > 0) { - response->availableSequenceNumbers = seqNumbers; - response->availableSequenceNumbersSize = available; - size_t i = 0; - UA_NotificationMessageEntry *nme; - TAILQ_FOREACH(nme, &sub->retransmissionQueue, listEntry) { - response->availableSequenceNumbers[i] = nme->message.sequenceNumber; - ++i; - } + UA_assert(sub->retransmissionQueueSize <= UA_MAX_RETRANSMISSIONQUEUESIZE); + UA_UInt32 seqNumbers[UA_MAX_RETRANSMISSIONQUEUESIZE]; + response->availableSequenceNumbers = seqNumbers; + response->availableSequenceNumbersSize = sub->retransmissionQueueSize; + size_t i = 0; + UA_NotificationMessageEntry *nme; + TAILQ_FOREACH(nme, &sub->retransmissionQueue, listEntry) { + response->availableSequenceNumbers[i] = nme->message.sequenceNumber; + ++i; } + UA_assert(i == sub->retransmissionQueueSize); /* Send the response */ - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Sending out a publish response " - "with %" PRIu32 " notifications", sub->subscriptionId, - notifications); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Sending out a publish response with %" PRIu32 + " notifications", notifications); sendResponse(server, sub->session, sub->session->header.channel, pre->requestId, (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); @@ -53934,13 +59083,25 @@ UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) { UA_PublishResponse_clear(&pre->response); UA_free(pre); + /* Update the diagnostics statistics */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->publishRequestCount++; + + UA_UInt32 sentDCN = (UA_UInt32) + (priorDataChangeNotifications - sub->dataChangeNotifications); + UA_UInt32 sentEN = (UA_UInt32)(priorEventNotifications - sub->eventNotifications); + sub->dataChangeNotificationsCount += sentDCN; + sub->eventNotificationsCount += sentEN; + sub->notificationsCount += (sentDCN + sentEN); +#endif + /* Repeat sending responses if there are more notifications to send */ if(moreNotifications) UA_Subscription_publish(server, sub); } UA_Boolean -UA_Subscription_reachedPublishReqLimit(UA_Server *server, UA_Session *session) { +UA_Session_reachedPublishReqLimit(UA_Server *server, UA_Session *session) { UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Reached number of publish request limit"); @@ -53949,7 +59110,8 @@ UA_Subscription_reachedPublishReqLimit(UA_Server *server, UA_Session *session) /* Cannot publish without a response */ if(!pre) { - UA_LOG_FATAL_SESSION(&server->config.logger, session, "No publish requests available"); + UA_LOG_FATAL_SESSION(&server->config.logger, session, + "No publish requests available"); return false; } @@ -53982,60 +59144,38 @@ UA_Subscription_reachedPublishReqLimit(UA_Server *server, UA_Session *session) UA_StatusCode Subscription_registerPublishCallback(UA_Server *server, UA_Subscription *sub) { - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, - "Subscription %" PRIu32 " | Register subscription " - "publishing callback", sub->subscriptionId); - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Register subscription publishing callback"); + UA_LOCK_ASSERT(&server->serviceMutex, 1); - if(sub->publishCallbackIsRegistered) + if(sub->publishCallbackId > 0) return UA_STATUSCODE_GOOD; UA_StatusCode retval = addRepeatedCallback(server, (UA_ServerCallback)publishCallback, - sub, (UA_UInt32)sub->publishingInterval, &sub->publishCallbackId); + sub, sub->publishingInterval, &sub->publishCallbackId); if(retval != UA_STATUSCODE_GOOD) return retval; - sub->publishCallbackIsRegistered = true; + UA_assert(sub->publishCallbackId > 0); return UA_STATUSCODE_GOOD; } void Subscription_unregisterPublishCallback(UA_Server *server, UA_Subscription *sub) { - UA_LOG_DEBUG_SESSION(&server->config.logger, sub->session, "Subscription %" PRIu32 " | " - "Unregister subscription publishing callback", sub->subscriptionId); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "Unregister subscription publishing callback"); - if(!sub->publishCallbackIsRegistered) + if(sub->publishCallbackId == 0) return; removeCallback(server, sub->publishCallbackId); - sub->publishCallbackIsRegistered = false; -} - -/* When the session has publish requests stored but the last subscription is - * deleted... Send out empty responses */ -void -UA_Subscription_answerPublishRequestsNoSubscription(UA_Server *server, UA_Session *session) { - /* No session or there are remaining subscriptions */ - if(!session || LIST_FIRST(&session->serverSubscriptions)) - return; - - /* Send a response for every queued request */ - UA_PublishResponseEntry *pre; - while((pre = UA_Session_dequeuePublishReq(session))) { - UA_PublishResponse *response = &pre->response; - response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION; - response->responseHeader.timestamp = UA_DateTime_now(); - sendResponse(server, session, session->header.channel, pre->requestId, - (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); - UA_PublishResponse_clear(response); - UA_free(pre); - } + sub->publishCallbackId = 0; } #endif /* UA_ENABLE_SUBSCRIPTIONS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_subscription_monitoreditem.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_subscription_monitoreditem.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -54046,6 +59186,7 @@ UA_Subscription_answerPublishRequestsNoSubscription(UA_Server *server, UA_Sessio * Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH * Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA * Copyright 2018 (c) Fabian Arndt, Root-Core + * Copyright 2020-2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) */ @@ -54057,175 +59198,357 @@ UA_Subscription_answerPublishRequestsNoSubscription(UA_Server *server, UA_Sessio #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS -static const UA_NodeId overflowEventType = +static const UA_NodeId eventQueueOverflowEventType = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_EVENTQUEUEOVERFLOWEVENTTYPE}}; -static const UA_NodeId simpleOverflowEventType = - {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_SIMPLEOVERFLOWEVENTTYPE}}; - -static UA_Boolean -UA_Notification_isOverflowEvent(UA_Server *server, UA_Notification *n) { - UA_MonitoredItem *mon = n->mon; - if(mon->attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) - return false; - - UA_EventFieldList *efl = &n->data.event.fields; - if(efl->eventFieldsSize >= 1 && - efl->eventFields[0].type == &UA_TYPES[UA_TYPES_NODEID] && - isNodeInTree(server, (const UA_NodeId *)efl->eventFields[0].data, - &overflowEventType, &subtypeId, 1)) { - return true; - } - - return false; -} /* The specification states in Part 4 5.12.1.5 that an EventQueueOverflowEvent * "is generated when the first Event has to be discarded [...] without * discarding any other event". So only generate one for all deleted events. */ static UA_StatusCode createEventOverflowNotification(UA_Server *server, UA_Subscription *sub, - UA_MonitoredItem *mon, UA_Notification *indicator) { - /* Avoid two redundant overflow events in a row */ - if((mon->discardOldest && UA_Notification_isOverflowEvent(server, indicator)) - || (!mon->discardOldest && TAILQ_PREV(indicator, NotificationQueue, listEntry) != NULL && - UA_Notification_isOverflowEvent(server, TAILQ_PREV(indicator, NotificationQueue, listEntry)))) - return UA_STATUSCODE_GOOD; + UA_MonitoredItem *mon) { + /* Avoid creating two adjacent overflow events */ + UA_Notification *indicator = NULL; + if(mon->parameters.discardOldest) { + indicator = TAILQ_FIRST(&mon->queue); + UA_assert(indicator); /* must exist */ + if(indicator->isOverflowEvent) + return UA_STATUSCODE_GOOD; + } else { + indicator = TAILQ_LAST(&mon->queue, NotificationQueue); + UA_assert(indicator); /* must exist */ + /* Skip the last element. It is the recently added notification that + * shall be kept. We know it is not an OverflowEvent. */ + UA_Notification *before = TAILQ_PREV(indicator, NotificationQueue, localEntry); + if(before && before->isOverflowEvent) + return UA_STATUSCODE_GOOD; + } - /* A notification is inserted into the queue which includes only the - * NodeId of the overflowEventType. It is up to the client to check for - * possible overflows. */ + /* A Notification is inserted into the queue which includes only the + * NodeId of the OverflowEventType. */ /* Allocate the notification */ - UA_Notification *overflowNotification = (UA_Notification *) - UA_malloc(sizeof(UA_Notification)); + UA_Notification *overflowNotification = UA_Notification_new(); if(!overflowNotification) return UA_STATUSCODE_BADOUTOFMEMORY; /* Set the notification fields */ + overflowNotification->isOverflowEvent = true; overflowNotification->mon = mon; - UA_EventFieldList_init(&overflowNotification->data.event.fields); - overflowNotification->data.event.fields.eventFields = UA_Variant_new(); - if(!overflowNotification->data.event.fields.eventFields) { + overflowNotification->data.event.clientHandle = mon->parameters.clientHandle; + overflowNotification->data.event.eventFields = UA_Variant_new(); + if(!overflowNotification->data.event.eventFields) { UA_free(overflowNotification); return UA_STATUSCODE_BADOUTOFMEMORY; } - overflowNotification->data.event.fields.eventFieldsSize = 1; + overflowNotification->data.event.eventFieldsSize = 1; UA_StatusCode retval = - UA_Variant_setScalarCopy(overflowNotification->data.event.fields.eventFields, - &simpleOverflowEventType, &UA_TYPES[UA_TYPES_NODEID]); + UA_Variant_setScalarCopy(overflowNotification->data.event.eventFields, + &eventQueueOverflowEventType, &UA_TYPES[UA_TYPES_NODEID]); if(retval != UA_STATUSCODE_GOOD) { - UA_EventFieldList_clear(&overflowNotification->data.event.fields); - UA_free(overflowNotification); + UA_Notification_delete(overflowNotification); return retval; } - /* Insert before the "indicator notification". This is either first in the + /* Insert before the removed notification. This is either first in the * queue (if the oldest notification was removed) or before the new event - * that remains the last element of the queue. */ - TAILQ_INSERT_BEFORE(indicator, overflowNotification, listEntry); + * that remains the last element of the queue. + * + * Ensure that the following is consistent with UA_Notification_enqueueMon + * and UA_Notification_enqueueSub! */ + TAILQ_INSERT_BEFORE(indicator, overflowNotification, localEntry); ++mon->eventOverflows; ++mon->queueSize; - TAILQ_NEXT(overflowNotification, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; - if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) { + /* Test for consistency */ + UA_assert(mon->queueSize >= mon->eventOverflows); + UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1); + + if(TAILQ_NEXT(indicator, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) { + /* Insert just before the indicator */ TAILQ_INSERT_BEFORE(indicator, overflowNotification, globalEntry); - ++sub->notificationQueueSize; - ++sub->eventNotifications; + } else { + /* The indicator was not reporting or not added yet. */ + if(!mon->parameters.discardOldest) { + /* Add last to the per-Subscription queue */ + TAILQ_INSERT_TAIL(&mon->subscription->notificationQueue, + overflowNotification, globalEntry); + } else { + /* Find the oldest reported element. Add before that. */ + while(indicator) { + indicator = TAILQ_PREV(indicator, NotificationQueue, localEntry); + if(!indicator) { + TAILQ_INSERT_TAIL(&mon->subscription->notificationQueue, + overflowNotification, globalEntry); + break; + } + if(TAILQ_NEXT(indicator, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) { + TAILQ_INSERT_BEFORE(indicator, overflowNotification, globalEntry); + break; + } + } + } } + + ++sub->notificationQueueSize; + ++sub->eventNotifications; + + /* Update the diagnostics statistics */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->eventQueueOverFlowCount++; +#endif + return UA_STATUSCODE_GOOD; } #endif -/* !!! The enqueue and dequeue operations need to match the reporting - * disable/enable logic in Operation_SetMonitoringMode !!! */ +/* Set the InfoBits that a datachange notification was removed */ +static void +setOverflowInfoBits(UA_MonitoredItem *mon) { + /* Only for queues with more than one element */ + if(mon->parameters.queueSize == 1) + return; + + UA_Notification *indicator = NULL; + if(mon->parameters.discardOldest) { + indicator = TAILQ_FIRST(&mon->queue); + } else { + indicator = TAILQ_LAST(&mon->queue, NotificationQueue); + } + UA_assert(indicator); /* must exist */ + + indicator->data.dataChange.value.hasStatus = true; + indicator->data.dataChange.value.status |= + (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW); +} +/* Remove the InfoBits when the queueSize was reduced to 1 */ void -UA_Notification_enqueue(UA_Server *server, UA_Subscription *sub, - UA_MonitoredItem *mon, UA_Notification *n) { +UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon) { + /* Don't consider queue size > 1 and Event MonitoredItems */ + if(mon->parameters.queueSize > 1 || + mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) + return; + + /* Get the first notification */ + UA_Notification *n = TAILQ_FIRST(&mon->queue); + if(!n) + return; + + /* Assertion that at most one notification is in the queue */ + UA_assert(n == TAILQ_LAST(&mon->queue, NotificationQueue)); + + /* Remve the Infobits */ + n->data.dataChange.value.status &= ~(UA_StatusCode) + (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW); +} + +UA_Notification * +UA_Notification_new(void) { + UA_Notification *n = (UA_Notification*)UA_calloc(1, sizeof(UA_Notification)); + if(n) { + /* Set the sentinel for a notification that is not enqueued */ + TAILQ_NEXT(n, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; + TAILQ_NEXT(n, localEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; + } + return n; +} + +static void UA_Notification_dequeueMon(UA_Notification *n); +static void UA_Notification_enqueueSub(UA_Notification *n); +static void UA_Notification_dequeueSub(UA_Notification *n); + +void +UA_Notification_delete(UA_Notification *n) { + UA_assert(n != UA_SUBSCRIPTION_QUEUE_SENTINEL); + if(n->mon) { + UA_Notification_dequeueMon(n); + UA_Notification_dequeueSub(n); + switch(n->mon->itemToMonitor.attributeId) { +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + case UA_ATTRIBUTEID_EVENTNOTIFIER: + UA_EventFieldList_clear(&n->data.event); + UA_EventFilterResult_clear(&n->result); + break; +#endif + default: + UA_MonitoredItemNotification_clear(&n->data.dataChange); + break; + } + } + UA_free(n); +} + +/* Add to the MonitoredItem queue, update all counters and then handle overflow */ +static void +UA_Notification_enqueueMon(UA_Server *server, UA_Notification *n) { + UA_MonitoredItem *mon = n->mon; + UA_assert(mon); + UA_assert(TAILQ_NEXT(n, localEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL); + /* Add to the MonitoredItem */ - TAILQ_INSERT_TAIL(&mon->queue, n, listEntry); + TAILQ_INSERT_TAIL(&mon->queue, n, localEntry); ++mon->queueSize; #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER && - UA_Notification_isOverflowEvent(server, n)) + if(n->isOverflowEvent) ++mon->eventOverflows; #endif - /* Add to the subscription if reporting is enabled */ - TAILQ_NEXT(n, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; - if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) { - TAILQ_INSERT_TAIL(&sub->notificationQueue, n, globalEntry); - ++sub->notificationQueueSize; -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - ++sub->eventNotifications; - } else -#endif - { - ++sub->dataChangeNotifications; - } - } + /* Test for consistency */ + UA_assert(mon->queueSize >= mon->eventOverflows); + UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1); /* Ensure enough space is available in the MonitoredItem. Do this only after * adding the new Notification. */ UA_MonitoredItem_ensureQueueSpace(server, mon); + + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, mon->subscription, + "MonitoredItem %" PRIi32 " | " + "Notification enqueued (Queue size %lu / %lu)", + mon->monitoredItemId, + (long unsigned)mon->queueSize, + (long unsigned)mon->parameters.queueSize); } void -UA_Notification_dequeue(UA_Server *server, UA_Notification *n) { +UA_Notification_enqueueSub(UA_Notification *n) { UA_MonitoredItem *mon = n->mon; + UA_assert(mon); + UA_Subscription *sub = mon->subscription; + UA_assert(sub); - /* Remove from the MonitoredItem queue */ -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER && - UA_Notification_isOverflowEvent(server, n)) - --mon->eventOverflows; -#endif - TAILQ_REMOVE(&mon->queue, n, listEntry); - --mon->queueSize; + if(TAILQ_NEXT(n, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) + return; + + /* Add to the subscription if reporting is enabled */ + TAILQ_INSERT_TAIL(&sub->notificationQueue, n, globalEntry); + ++sub->notificationQueueSize; - /* Remove from the subscription's queue */ - if(TAILQ_NEXT(n, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) { + switch(mon->itemToMonitor.attributeId) { #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - --sub->eventNotifications; - } else + case UA_ATTRIBUTEID_EVENTNOTIFIER: + ++sub->eventNotifications; + break; #endif - { - --sub->dataChangeNotifications; + default: + ++sub->dataChangeNotifications; + break; + } +} + +void +UA_Notification_enqueueAndTrigger(UA_Server *server, UA_Notification *n) { + UA_MonitoredItem *mon = n->mon; + UA_Subscription *sub = mon->subscription; + UA_assert(sub); /* This function is never called for local MonitoredItems */ + + /* If reporting or (sampled+triggered), enqueue into the Subscription first + * and then into the MonitoredItem. UA_MonitoredItem_ensureQueueSpace + * (called within UA_Notification_enqueueMon) assumes the notification is + * already in the Subscription's publishing queue. */ + if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING || + (mon->monitoringMode == UA_MONITORINGMODE_SAMPLING && + mon->triggeredUntil > UA_DateTime_nowMonotonic())) { + UA_Notification_enqueueSub(n); + mon->triggeredUntil = UA_INT64_MIN; + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, mon->subscription, + "Notification enqueued (Queue size %lu)", + (long unsigned)mon->subscription->notificationQueueSize); + } + + /* Insert into the MonitoredItem. This checks the queue size and + * handles overflow. */ + UA_Notification_enqueueMon(server, n); + + for(size_t i = mon->triggeringLinksSize - 1; i < mon->triggeringLinksSize; i--) { + /* Get the triggered MonitoredItem. Remove the link if the MI doesn't exist. */ + UA_MonitoredItem *triggeredMon = + UA_Subscription_getMonitoredItem(sub, mon->triggeringLinks[i]); + if(!triggeredMon) { + UA_MonitoredItem_removeLink(sub, mon, mon->triggeringLinks[i]); + continue; } - /* - see open issue #2114: - in the function UA_MonitoredItem_ensureQueueSpace, a greater overflow event size - than event queue size will result in false assertion. - to fix this problem, we assume that only one overflow event is allowed, so by - dequeueing a notification, we remove the overflow event by setting its size to 0. - */ - //mon->eventOverflows = 0; + /* Only sampling MonitoredItems receive a trigger. Reporting + * MonitoredItems send out Notifications anyway and disabled + * MonitoredItems don't create samples to send. */ + if(triggeredMon->monitoringMode != UA_MONITORINGMODE_SAMPLING) + continue; - TAILQ_REMOVE(&sub->notificationQueue, n, globalEntry); - --sub->notificationQueueSize; + /* Get the latest sampled Notification from the triggered MonitoredItem. + * Enqueue for publication. */ + UA_Notification *n2 = TAILQ_LAST(&triggeredMon->queue, NotificationQueue); + if(n2) + UA_Notification_enqueueSub(n2); + + /* The next Notification within the publishing interval is going to be + * published as well. (Falsely) assume that the publishing cycle has + * started right now, so that we don't have to loop over MonitoredItems + * to deactivate the triggering after the publishing cycle. */ + triggeredMon->triggeredUntil = UA_DateTime_nowMonotonic() + + (UA_DateTime)(sub->publishingInterval * (UA_Double)UA_DATETIME_MSEC); + + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %u triggers MonitoredItem %u", + mon->monitoredItemId, triggeredMon->monitoredItemId); } } -void -UA_Notification_delete(UA_Notification *n) { +/* Remove from the MonitoredItem queue and adjust all counters */ +static void +UA_Notification_dequeueMon(UA_Notification *n) { + UA_MonitoredItem *mon = n->mon; + UA_assert(mon); + + if(TAILQ_NEXT(n, localEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL) + return; + + /* Remove from the MonitoredItem queue */ #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + if(n->isOverflowEvent) + --mon->eventOverflows; +#endif + + TAILQ_REMOVE(&mon->queue, n, localEntry); + --mon->queueSize; + + /* Test for consistency */ + UA_assert(mon->queueSize >= mon->eventOverflows); + UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1); + + /* Reset the sentintel */ + TAILQ_NEXT(n, localEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; +} + +void +UA_Notification_dequeueSub(UA_Notification *n) { + if(TAILQ_NEXT(n, globalEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL) + return; + UA_MonitoredItem *mon = n->mon; - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - UA_EventFieldList_clear(&n->data.event.fields); - /* EventFilterResult currently isn't being used - * UA_EventFilterResult_delete(notification->data.event->result); */ - } else + UA_assert(mon); + UA_Subscription *sub = mon->subscription; + UA_assert(sub); + + switch(mon->itemToMonitor.attributeId) { +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + case UA_ATTRIBUTEID_EVENTNOTIFIER: + --sub->eventNotifications; + break; #endif - { - UA_DataValue_clear(&n->data.value); + default: + --sub->dataChangeNotifications; + break; } - UA_free(n); + + TAILQ_REMOVE(&sub->notificationQueue, n, globalEntry); + --sub->notificationQueueSize; + + /* Reset the sentinel */ + TAILQ_NEXT(n, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL; } /*****************/ @@ -54233,204 +59556,458 @@ UA_Notification_delete(UA_Notification *n) { /*****************/ void -UA_MonitoredItem_init(UA_MonitoredItem *mon, UA_Subscription *sub) { +UA_MonitoredItem_init(UA_MonitoredItem *mon) { memset(mon, 0, sizeof(UA_MonitoredItem)); - mon->subscription = sub; + mon->next = (UA_MonitoredItem*)~0; /* Not added to a node */ TAILQ_INIT(&mon->queue); + mon->triggeredUntil = UA_INT64_MIN; } -void -UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem) { - UA_LOCK_ASSERT(server->serviceMutex, 1); +static UA_StatusCode +addMonitoredItemBackpointer(UA_Server *server, UA_Session *session, + UA_Node *node, void *data) { + UA_MonitoredItem *mon = (UA_MonitoredItem*)data; + UA_assert(mon != (UA_MonitoredItem*)~0); + mon->next = node->head.monitoredItems; + node->head.monitoredItems = mon; + return UA_STATUSCODE_GOOD; +} - /* Remove the sampling callback */ - UA_MonitoredItem_unregisterSampleCallback(server, monitoredItem); - - /* Remove the queued notifications if attached to a subscription (not a - * local MonitoredItem) */ - if(monitoredItem->subscription) { - UA_Notification *notification, *notification_tmp; - TAILQ_FOREACH_SAFE(notification, &monitoredItem->queue, - listEntry, notification_tmp) { - /* Remove the item from the queues and free the memory */ - UA_Notification_dequeue(server, notification); - UA_Notification_delete(notification); +static UA_StatusCode +removeMonitoredItemBackPointer(UA_Server *server, UA_Session *session, + UA_Node *node, void *data) { + if(!node->head.monitoredItems) + return UA_STATUSCODE_GOOD; + + /* Edge case that it's the first element */ + UA_MonitoredItem *remove = (UA_MonitoredItem*)data; + if(node->head.monitoredItems == remove) { + node->head.monitoredItems = remove->next; + remove->next = (UA_MonitoredItem*)~0; + return UA_STATUSCODE_GOOD; + } + + UA_MonitoredItem *prev = node->head.monitoredItems; + UA_MonitoredItem *entry = prev->next; + for(; entry != NULL; prev = entry, entry = entry->next) { + if(entry == remove) { + prev->next = entry->next; + remove->next = (UA_MonitoredItem*)~0; + break; } } -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(monitoredItem->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - /* Remove the monitored item from the node queue */ - UA_Server_editNode(server, NULL, &monitoredItem->monitoredNodeId, - UA_MonitoredItem_removeNodeEventCallback, monitoredItem); - UA_EventFilter_clear(&monitoredItem->filter.eventFilter); - } else -#endif - { - /* UA_DataChangeFilter does not hold dynamic content we need to free */ - /* UA_DataChangeFilter_clear(&monitoredItem->filter.dataChangeFilter); */ + return UA_STATUSCODE_GOOD; +} + +void +UA_Server_registerMonitoredItem(UA_Server *server, UA_MonitoredItem *mon) { + if(mon->registered) + return; + + /* Register in Subscription and Server */ + UA_Subscription *sub = mon->subscription; + if(sub) { + mon->monitoredItemId = ++sub->lastMonitoredItemId; + mon->subscription = sub; + sub->monitoredItemsSize++; + LIST_INSERT_HEAD(&sub->monitoredItems, mon, listEntry); + } else { + mon->monitoredItemId = ++server->lastLocalMonitoredItemId; + LIST_INSERT_HEAD(&server->localMonitoredItems, mon, listEntry); + } + server->monitoredItemsSize++; + + /* Register the MonitoredItem in userland */ + if(server->config.monitoredItemRegisterCallback) { + UA_Session *session = &server->adminSession; + if(sub) + session = sub->session; + + void *targetContext = NULL; + getNodeContext(server, mon->itemToMonitor.nodeId, &targetContext); + UA_UNLOCK(&server->serviceMutex); + server->config.monitoredItemRegisterCallback(server, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &mon->itemToMonitor.nodeId, + targetContext, + mon->itemToMonitor.attributeId, false); + UA_LOCK(&server->serviceMutex); } + mon->registered = true; +} + +static void +UA_Server_unregisterMonitoredItem(UA_Server *server, UA_MonitoredItem *mon) { + if(!mon->registered) + return; + + UA_Subscription *sub = mon->subscription; + UA_LOG_INFO_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %" PRIi32 " | Deleting the MonitoredItem", + mon->monitoredItemId); + /* Deregister MonitoredItem in userland */ - if(server->config.monitoredItemRegisterCallback && monitoredItem->registered) { - /* Get the session context. Local MonitoredItems don't have a subscription. */ - UA_Session *session = NULL; - if(monitoredItem->subscription) - session = monitoredItem->subscription->session; - if(!session) - session = &server->adminSession; + if(server->config.monitoredItemRegisterCallback) { + UA_Session *session = &server->adminSession; + if(sub) + session = sub->session; - /* Get the node context */ void *targetContext = NULL; - getNodeContext(server, monitoredItem->monitoredNodeId, &targetContext); + getNodeContext(server, mon->itemToMonitor.nodeId, &targetContext); + UA_UNLOCK(&server->serviceMutex); + server->config.monitoredItemRegisterCallback(server, + session ? &session->sessionId : NULL, + session ? session->sessionHandle : NULL, + &mon->itemToMonitor.nodeId, + targetContext, + mon->itemToMonitor.attributeId, true); + UA_LOCK(&server->serviceMutex); + } + + /* Deregister in Subscription and server */ + if(sub) + sub->monitoredItemsSize--; + LIST_REMOVE(mon, listEntry); /* Also for LocalMonitoredItems */ + server->monitoredItemsSize--; + + mon->registered = false; +} + +UA_StatusCode +UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon, + UA_MonitoringMode monitoringMode) { + /* Check if the MonitoringMode is valid or not */ + if(monitoringMode > UA_MONITORINGMODE_REPORTING) + return UA_STATUSCODE_BADMONITORINGMODEINVALID; + + /* Set the MonitoringMode, store the old mode */ + UA_MonitoringMode oldMode = mon->monitoringMode; + mon->monitoringMode = monitoringMode; - /* Deregister */ - UA_UNLOCK(server->serviceMutex); - server->config.monitoredItemRegisterCallback(server, &session->sessionId, - session->sessionHandle, - &monitoredItem->monitoredNodeId, - targetContext, monitoredItem->attributeId, true); - UA_LOCK(server->serviceMutex); + UA_Notification *notification; + /* Reporting is disabled. This causes all Notifications to be dequeued and + * deleted. Also remove the last samples so that we immediately generate a + * Notification when re-activated. */ + if(mon->monitoringMode == UA_MONITORINGMODE_DISABLED) { + UA_Notification *notification_tmp; + UA_MonitoredItem_unregisterSampling(server, mon); + TAILQ_FOREACH_SAFE(notification, &mon->queue, localEntry, notification_tmp) { + UA_Notification_delete(notification); + } + UA_DataValue_clear(&mon->lastValue); + return UA_STATUSCODE_GOOD; } - /* Remove the monitored item */ - if(monitoredItem->listEntry.le_prev != NULL) - LIST_REMOVE(monitoredItem, listEntry); - UA_String_clear(&monitoredItem->indexRange); - UA_ByteString_clear(&monitoredItem->lastSampledValue); - UA_Variant_clear(&monitoredItem->lastValue); - UA_NodeId_clear(&monitoredItem->monitoredNodeId); + /* When reporting is enabled, put all notifications that were already + * sampled into the global queue of the subscription. When sampling is + * enabled, remove all notifications from the global queue. !!! This needs + * to be the same operation as in UA_Notification_enqueue !!! */ + if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) { + /* Make all notifications reporting. Re-enqueue to ensure they have the + * right order if some notifications are already reported by a trigger + * link. */ + TAILQ_FOREACH(notification, &mon->queue, localEntry) { + UA_Notification_dequeueSub(notification); + UA_Notification_enqueueSub(notification); + } + } else /* mon->monitoringMode == UA_MONITORINGMODE_SAMPLING */ { + /* Make all notifications non-reporting */ + TAILQ_FOREACH(notification, &mon->queue, localEntry) + UA_Notification_dequeueSub(notification); + } + + /* Register the sampling callback with an interval. If registering the + * sampling callback failed, set to disabled. But don't delete the current + * notifications. */ + UA_StatusCode res = UA_MonitoredItem_registerSampling(server, mon); + if(res != UA_STATUSCODE_GOOD) { + mon->monitoringMode = UA_MONITORINGMODE_DISABLED; + return res; + } - /* No actual callback, just remove the structure */ - monitoredItem->delayedFreePointers.callback = NULL; - UA_WorkQueue_enqueueDelayed(&server->workQueue, &monitoredItem->delayedFreePointers); + /* Manually create the first sample if the MonitoredItem was disabled, the + * MonitoredItem is now sampling (or reporting) and it is not an + * Event-MonitoredItem */ + if(oldMode == UA_MONITORINGMODE_DISABLED && + mon->monitoringMode > UA_MONITORINGMODE_DISABLED && + mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) + monitoredItem_sampleCallback(server, mon); + + return UA_STATUSCODE_GOOD; } -UA_StatusCode +void +UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *mon) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + /* Remove the sampling callback */ + UA_MonitoredItem_unregisterSampling(server, mon); + + UA_assert(mon->next == (UA_MonitoredItem*)~0); /* Not attached to any node */ + + /* Deregister in Server and Subscription */ + if(mon->registered) + UA_Server_unregisterMonitoredItem(server, mon); + + /* Remove the TriggeringLinks */ + if(mon->triggeringLinksSize > 0) { + UA_free(mon->triggeringLinks); + mon->triggeringLinks = NULL; + mon->triggeringLinksSize = 0; + } + + /* Remove the queued notifications attached to the subscription */ + UA_Notification *notification, *notification_tmp; + TAILQ_FOREACH_SAFE(notification, &mon->queue, localEntry, notification_tmp) { + UA_Notification_delete(notification); + } + + /* Remove the settings */ + UA_ReadValueId_clear(&mon->itemToMonitor); + UA_MonitoringParameters_clear(&mon->parameters); + + /* Remove the last samples */ + UA_DataValue_clear(&mon->lastValue); + + /* Add a delayed callback to remove the MonitoredItem when the current jobs + * have completed. This is needed to allow that a local MonitoredItem can + * remove itself in the callback. */ + mon->delayedFreePointers.callback = NULL; + mon->delayedFreePointers.application = server; + mon->delayedFreePointers.data = NULL; + mon->delayedFreePointers.nextTime = UA_DateTime_nowMonotonic() + 1; + mon->delayedFreePointers.interval = 0; + UA_Timer_addTimerEntry(&server->timer, &mon->delayedFreePointers, NULL); +} + +void UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon) { - /* Assert: The eventoverflow are counted in the queue size; There can be - * only one eventoverflow more than normal entries */ + /* There can be only one EventOverflow more than normal entries. Because + * EventOverflows are never adjacent. */ UA_assert(mon->queueSize >= mon->eventOverflows); UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1); - /* Nothing to do */ - if(mon->queueSize - mon->eventOverflows <= mon->maxQueueSize) - return UA_STATUSCODE_GOOD; + /* Always attached to a Subscription (no local MonitoredItem) */ + UA_Subscription *sub = mon->subscription; + UA_assert(sub); -#ifdef __clang_analyzer__ - return UA_STATUSCODE_GOOD; -#endif + /* Nothing to do */ + if(mon->queueSize - mon->eventOverflows <= mon->parameters.queueSize) + return; - /* Remove notifications until the queue size is reached */ - UA_Subscription *sub = mon->subscription; - while(mon->queueSize - mon->eventOverflows > mon->maxQueueSize) { - /* At least two notifications that are not eventOverflows in the queue */ + /* Remove notifications until the required queue size is reached */ + UA_Boolean reporting = false; + size_t remove = mon->queueSize - mon->eventOverflows - mon->parameters.queueSize; + while(remove > 0) { + /* The minimum queue size (without EventOverflows) is 1. At least two + * notifications that are not EventOverflows are in the queue. */ UA_assert(mon->queueSize - mon->eventOverflows >= 2); /* Select the next notification to delete. Skip over overflow events. */ UA_Notification *del = NULL; - if(mon->discardOldest) { + if(mon->parameters.discardOldest) { /* Remove the oldest */ del = TAILQ_FIRST(&mon->queue); -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - while(UA_Notification_isOverflowEvent(server, del)) - del = TAILQ_NEXT(del, listEntry); /* skip overflow events */ +#if defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS) && !defined(__clang_analyzer__) + while(del->isOverflowEvent) + del = TAILQ_NEXT(del, localEntry); /* skip overflow events */ #endif } else { /* Remove the second newest (to keep the up-to-date notification). * The last entry is not an OverflowEvent -- we just added it. */ del = TAILQ_LAST(&mon->queue, NotificationQueue); - del = TAILQ_PREV(del, NotificationQueue, listEntry); -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - while(UA_Notification_isOverflowEvent(server, del)) - del = TAILQ_PREV(del, NotificationQueue, listEntry); /* skip overflow events */ + del = TAILQ_PREV(del, NotificationQueue, localEntry); +#if defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS) && !defined(__clang_analyzer__) + while(del->isOverflowEvent) + del = TAILQ_PREV(del, NotificationQueue, localEntry); /* skip overflow events */ #endif } UA_assert(del); /* There must have been one entry that can be deleted */ - /* If reporting is activated (entries are also in the subscriptions - * global queue): Move the entry after del in the per-MonitoredItem - * queue right after del in the global queue. (It is already right after - * del in the per-MonitoredItem queue.) This is required so we don't - * starve MonitoredItems with a high sampling interval by always - * removing their first appearance in the gloal queue for the - * Subscription. */ + /* Only create OverflowEvents (and set InfoBits) if the notification + * that is removed is reported */ + if(TAILQ_NEXT(del, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) + reporting = true; + + /* Move the entry after del in the per-MonitoredItem queue right after + * del in the per-Subscription queue. So we don't starve MonitoredItems + * with a high sampling interval in the Subscription queue by always + * removing their first appearance in the per-Subscription queue. + * + * With MonitoringMode == SAMPLING, the Notifications are not (all) in + * the per-Subscription queue. Don't reinsert in that case. + * + * For the reinsertion to work, first insert into the per-Subscription + * queue. */ if(TAILQ_NEXT(del, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) { - UA_Notification *after_del = TAILQ_NEXT(del, listEntry); + UA_Notification *after_del = TAILQ_NEXT(del, localEntry); UA_assert(after_del); /* There must be one remaining element after del */ - TAILQ_REMOVE(&sub->notificationQueue, after_del, globalEntry); - TAILQ_INSERT_AFTER(&sub->notificationQueue, del, after_del, globalEntry); + if(TAILQ_NEXT(after_del, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) { + TAILQ_REMOVE(&sub->notificationQueue, after_del, globalEntry); + TAILQ_INSERT_AFTER(&sub->notificationQueue, del, after_del, globalEntry); + } } - /* Delete the notification */ - UA_Notification_dequeue(server, del); + remove--; + + /* Delete the notification and remove it from the queues */ UA_Notification_delete(del); - } - /* Get the element where the overflow shall be announced (infobits or - * overflowevent) */ - UA_Notification *indicator; - if(mon->discardOldest) - indicator = TAILQ_FIRST(&mon->queue); - else - indicator = TAILQ_LAST(&mon->queue, NotificationQueue); - UA_assert(indicator); + /* Update the subscription diagnostics statistics */ +#ifdef UA_ENABLE_DIAGNOSTICS + sub->monitoringQueueOverflowCount++; +#endif + + /* Assertions to help Clang's scan-analyzer */ + UA_assert(del != TAILQ_FIRST(&mon->queue)); + UA_assert(del != TAILQ_LAST(&mon->queue, NotificationQueue)); + UA_assert(del != TAILQ_PREV(TAILQ_LAST(&mon->queue, NotificationQueue), + NotificationQueue, localEntry)); + } - /* Create an overflow notification */ + /* Leave an entry to indicate that notifications were removed */ + if(reporting) { #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { - return createEventOverflowNotification(server, sub, mon, indicator); - } else + if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) + createEventOverflowNotification(server, sub, mon); + else #endif - { - /* Set the infobits of a datachange notification */ - if(mon->maxQueueSize > 1) { - /* Add the infobits either to the newest or the new last entry */ - indicator->data.value.hasStatus = true; - indicator->data.value.status |= - (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW); - } + setOverflowInfoBits(mon); } - return UA_STATUSCODE_GOOD; } UA_StatusCode -UA_MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon) { - UA_LOCK_ASSERT(server->serviceMutex, 1); +UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(mon->sampleCallbackIsRegistered) return UA_STATUSCODE_GOOD; - /* Only DataChange MonitoredItems have a callback with a sampling interval */ - if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) - return UA_STATUSCODE_GOOD; + UA_assert(mon->next == (UA_MonitoredItem*)~0); /* Not registered in a node */ + + /* Only DataChange MonitoredItems with a positive sampling interval have a + * repeated callback. Other MonitoredItems are attached to the Node in a + * linked list of backpointers. */ + UA_StatusCode res; + if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER || + mon->parameters.samplingInterval == 0.0) { + UA_Subscription *sub = mon->subscription; + UA_Session *session = &server->adminSession; + if(sub) + session = sub->session; + res = UA_Server_editNode(server, session, &mon->itemToMonitor.nodeId, + addMonitoredItemBackpointer, mon); + } else { + res = addRepeatedCallback(server, + (UA_ServerCallback)UA_MonitoredItem_sampleCallback, + mon, mon->parameters.samplingInterval, + &mon->sampleCallbackId); + } - UA_StatusCode retval = - addRepeatedCallback(server, (UA_ServerCallback)UA_MonitoredItem_sampleCallback, - mon, mon->samplingInterval, &mon->sampleCallbackId); - if(retval == UA_STATUSCODE_GOOD) + if(res == UA_STATUSCODE_GOOD) mon->sampleCallbackIsRegistered = true; - return retval; + return res; } void -UA_MonitoredItem_unregisterSampleCallback(UA_Server *server, UA_MonitoredItem *mon) { - UA_LOCK_ASSERT(server->serviceMutex, 1); +UA_MonitoredItem_unregisterSampling(UA_Server *server, UA_MonitoredItem *mon) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); if(!mon->sampleCallbackIsRegistered) return; - removeCallback(server, mon->sampleCallbackId); + mon->sampleCallbackIsRegistered = false; + + /* Check for mon->next and not the samplingInterval. Because that might + * currently be changed. */ + if(mon->next != (UA_MonitoredItem*)~0) { + /* Added to a node */ + UA_Subscription *sub = mon->subscription; + UA_Session *session = &server->adminSession; + if(sub) + session = sub->session; + UA_Server_editNode(server, session, &mon->itemToMonitor.nodeId, + removeMonitoredItemBackPointer, mon); + } else { + /* Registered with a repeated callback */ + removeCallback(server, mon->sampleCallbackId); + } +} + +UA_StatusCode +UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon, UA_UInt32 linkId) { + /* Find the index */ + size_t i = 0; + for(; i < mon->triggeringLinksSize; i++) { + if(mon->triggeringLinks[i] == linkId) + break; + } + + /* Not existing / already removed */ + if(i == mon->triggeringLinksSize) + return UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + + /* Remove the link */ + mon->triggeringLinksSize--; + if(mon->triggeringLinksSize == 0) { + UA_free(mon->triggeringLinks); + mon->triggeringLinks = NULL; + } else { + mon->triggeringLinks[i] = mon->triggeringLinks[mon->triggeringLinksSize]; + UA_UInt32 *tmpLinks = (UA_UInt32*) + UA_realloc(mon->triggeringLinks, mon->triggeringLinksSize * sizeof(UA_UInt32)); + if(tmpLinks) + mon->triggeringLinks = tmpLinks; + } + + /* Does the target MonitoredItem exist? This is stupid, but the CTT wants us + * to to this. We don't auto-remove links together with the target + * MonitoredItem. Links to removed MonitoredItems are removed when the link + * triggers and the target no longer exists. */ + UA_MonitoredItem *mon2 = UA_Subscription_getMonitoredItem(sub, linkId); + if(!mon2) + return UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon, UA_UInt32 linkId) { + /* Does the target MonitoredItem exist? */ + UA_MonitoredItem *mon2 = UA_Subscription_getMonitoredItem(sub, linkId); + if(!mon2) + return UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + + /* Does the link already exist? */ + for(size_t i = 0 ; i < mon->triggeringLinksSize; i++) { + if(mon->triggeringLinks[i] == linkId) + return UA_STATUSCODE_GOOD; + } + + /* Allocate the memory */ + UA_UInt32 *tmpLinkIds = (UA_UInt32*) + UA_realloc(mon->triggeringLinks, (mon->triggeringLinksSize + 1) * sizeof(UA_UInt32)); + if(!tmpLinkIds) + return UA_STATUSCODE_BADOUTOFMEMORY; + mon->triggeringLinks = tmpLinkIds; + + /* Add the link */ + mon->triggeringLinks[mon->triggeringLinksSize] = linkId; + mon->triggeringLinksSize++; + return UA_STATUSCODE_GOOD; } #endif /* UA_ENABLE_SUBSCRIPTIONS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_subscription_datachange.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_subscription_datachange.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) * Copyright 2017 (c) Stefan Profanter, fortiss GmbH * Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH * Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA @@ -54440,240 +60017,170 @@ UA_MonitoredItem_unregisterSampleCallback(UA_Server *server, UA_MonitoredItem *m #ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ -#define UA_VALUENCODING_MAXSTACK 512 +/* Detect value changes outside the deadband */ +#define UA_DETECT_DEADBAND(TYPE) do { \ + TYPE v1 = *(const TYPE*)data1; \ + TYPE v2 = *(const TYPE*)data2; \ + TYPE diff = (v1 > v2) ? (TYPE)(v1 - v2) : (TYPE)(v2 - v1); \ + return ((UA_Double)diff > deadband); \ +} while(false); -/* Convert to double first. We might loose differences for large Int64 that - * cannot be precisely expressed as double. */ static UA_Boolean -outOfDeadBand(const void *data1, const void *data2, - const UA_DataType *type, const UA_Double deadband) { - UA_Double v; - if(type == &UA_TYPES[UA_TYPES_BOOLEAN]) { - v = (UA_Double)*(const UA_Boolean*)data1 - (UA_Double)*(const UA_Boolean*)data2; - } else if(type == &UA_TYPES[UA_TYPES_SBYTE]) { - v = (UA_Double)*(const UA_SByte*)data1 - (UA_Double)*(const UA_SByte*)data2; - } else if(type == &UA_TYPES[UA_TYPES_BYTE]) { - v = (UA_Double)*(const UA_Byte*)data1 - (UA_Double)*(const UA_Byte*)data2; - } else if(type == &UA_TYPES[UA_TYPES_INT16]) { - v = (UA_Double)*(const UA_Int16*)data1 - (UA_Double)*(const UA_Int16*)data2; - } else if(type == &UA_TYPES[UA_TYPES_UINT16]) { - v = (UA_Double)*(const UA_UInt16*)data1 - (UA_Double)*(const UA_UInt16*)data2; - } else if(type == &UA_TYPES[UA_TYPES_INT32]) { - v = (UA_Double)*(const UA_Int32*)data1 - (UA_Double)*(const UA_Int32*)data2; - } else if(type == &UA_TYPES[UA_TYPES_UINT32]) { - v = (UA_Double)*(const UA_UInt32*)data1 - (UA_Double)*(const UA_UInt32*)data2; - } else if(type == &UA_TYPES[UA_TYPES_INT64]) { - v = (UA_Double)*(const UA_Int64*)data1 - (UA_Double)*(const UA_Int64*)data2; - } else if(type == &UA_TYPES[UA_TYPES_UINT64]) { - v = (UA_Double)*(const UA_UInt64*)data1 - (UA_Double)*(const UA_UInt64*)data2; - } else if(type == &UA_TYPES[UA_TYPES_FLOAT]) { - v = (UA_Double)*(const UA_Float*)data1 - (UA_Double)*(const UA_Float*)data2; - } else if(type == &UA_TYPES[UA_TYPES_DOUBLE]) { - v = (UA_Double)*(const UA_Double*)data1 - (UA_Double)*(const UA_Double*)data2; +detectScalarDeadBand(const void *data1, const void *data2, + const UA_DataType *type, const UA_Double deadband) { + if(type->typeKind == UA_DATATYPEKIND_SBYTE) { + UA_DETECT_DEADBAND(UA_SByte); + } else if(type->typeKind == UA_DATATYPEKIND_BYTE) { + UA_DETECT_DEADBAND(UA_Byte); + } else if(type->typeKind == UA_DATATYPEKIND_INT16) { + UA_DETECT_DEADBAND(UA_Int16); + } else if(type->typeKind == UA_DATATYPEKIND_UINT16) { + UA_DETECT_DEADBAND(UA_UInt16); + } else if(type->typeKind == UA_DATATYPEKIND_INT32) { + UA_DETECT_DEADBAND(UA_Int32); + } else if(type->typeKind == UA_DATATYPEKIND_UINT32) { + UA_DETECT_DEADBAND(UA_UInt32); + } else if(type->typeKind == UA_DATATYPEKIND_INT64) { + UA_DETECT_DEADBAND(UA_Int64); + } else if(type->typeKind == UA_DATATYPEKIND_UINT64) { + UA_DETECT_DEADBAND(UA_UInt64); + } else if(type->typeKind == UA_DATATYPEKIND_FLOAT) { + UA_DETECT_DEADBAND(UA_Float); + } else if(type->typeKind == UA_DATATYPEKIND_DOUBLE) { + UA_DETECT_DEADBAND(UA_Double); } else { - return false; + return false; /* Not a known numerical type */ } - if(v < 0.0) - v = -v; - return (v > deadband); } static UA_Boolean -updateNeededForFilteredValue(const UA_Variant *value, const UA_Variant *oldValue, - const UA_Double deadbandValue) { +detectVariantDeadband(const UA_Variant *value, const UA_Variant *oldValue, + const UA_Double deadbandValue) { if(value->arrayLength != oldValue->arrayLength) return true; - if(value->type != oldValue->type) return true; - size_t length = 1; if(!UA_Variant_isScalar(value)) length = value->arrayLength; uintptr_t data = (uintptr_t)value->data; + uintptr_t oldData = (uintptr_t)oldValue->data; + UA_UInt32 memSize = value->type->memSize; for(size_t i = 0; i < length; ++i) { - if(outOfDeadBand((const void*)data, oldValue->data, value->type, deadbandValue)) + if(detectScalarDeadBand((const void*)data, (const void*)oldData, + value->type, deadbandValue)) return true; - data += value->type->memSize; + data += memSize; + oldData += memSize; } - return false; } -/* When a change is detected, encoding contains the heap-allocated binary - * encoded value. The default for changed is false. */ -static UA_StatusCode -detectValueChangeWithFilter(UA_Server *server, UA_Session *session, UA_MonitoredItem *mon, - UA_DataValue *value, UA_ByteString *encoding, UA_Boolean *changed) { - /* Check for absolute deadband */ - if(UA_DataType_isNumeric(value->value.type) && - mon->filter.dataChangeFilter.deadbandType == UA_DEADBANDTYPE_ABSOLUTE) { - UA_assert(value->value.type); - if(mon->filter.dataChangeFilter.trigger == UA_DATACHANGETRIGGER_STATUSVALUE || - mon->filter.dataChangeFilter.trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP) { - if(!updateNeededForFilteredValue(&value->value, &mon->lastValue, - mon->filter.dataChangeFilter.deadbandValue)) - return UA_STATUSCODE_GOOD; - } - } - - /* Stack-allocate some memory for the value encoding. We might heap-allocate - * more memory if needed. This is just enough for scalars and small - * structures. */ - UA_STACKARRAY(UA_Byte, stackValueEncoding, UA_VALUENCODING_MAXSTACK); - UA_ByteString valueEncoding; - valueEncoding.data = stackValueEncoding; - valueEncoding.length = UA_VALUENCODING_MAXSTACK; - - /* Encode the value */ - UA_Byte *bufPos = valueEncoding.data; - const UA_Byte *bufEnd = &valueEncoding.data[valueEncoding.length]; - UA_StatusCode retval = UA_encodeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE], - &bufPos, &bufEnd, NULL, NULL); - if(retval == UA_STATUSCODE_BADENCODINGERROR) { - size_t binsize = UA_calcSizeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE]); - if(binsize == 0) - return UA_STATUSCODE_BADENCODINGERROR; +static UA_Boolean +detectValueChange(UA_Server *server, UA_MonitoredItem *mon, + const UA_DataValue *value) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); - if(binsize > UA_VALUENCODING_MAXSTACK) { - retval = UA_ByteString_allocBuffer(&valueEncoding, binsize); - if(retval == UA_STATUSCODE_GOOD) { - bufPos = valueEncoding.data; - bufEnd = &valueEncoding.data[valueEncoding.length]; - retval = UA_encodeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE], - &bufPos, &bufEnd, NULL, NULL); - } - } - } - if(retval != UA_STATUSCODE_GOOD) { - if(valueEncoding.data != stackValueEncoding) - UA_ByteString_clear(&valueEncoding); - return retval; + /* Status changes are always reported */ + if(value->hasStatus != mon->lastValue.hasStatus || + value->status != mon->lastValue.status) { + return true; } - /* Has the value changed? */ - valueEncoding.length = (uintptr_t)bufPos - (uintptr_t)valueEncoding.data; - *changed = (!mon->lastSampledValue.data || - !UA_String_equal(&valueEncoding, &mon->lastSampledValue)); - - /* No change */ - if(!(*changed)) { - if(valueEncoding.data != stackValueEncoding) - UA_ByteString_clear(&valueEncoding); - return UA_STATUSCODE_GOOD; - } + /* Default trigger is Status + Value */ + UA_DataChangeTrigger trigger = UA_DATACHANGETRIGGER_STATUSVALUE; - /* Change detected. Copy encoding on the heap if necessary. */ - if(valueEncoding.data == stackValueEncoding) - return UA_ByteString_copy(&valueEncoding, encoding); + /* Use the configured trigger */ + const UA_DataChangeFilter *dcf = NULL; + const UA_ExtensionObject *filter = &mon->parameters.filter; + if(filter->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) { + dcf = (UA_DataChangeFilter*)filter->content.decoded.data; + trigger = dcf->trigger; + } - *encoding = valueEncoding; - return UA_STATUSCODE_GOOD; -} + /* The status was already tested above */ + if(trigger == UA_DATACHANGETRIGGER_STATUS) + return false; -/* Has this sample changed from the last one? The method may allocate additional - * space for the encoding buffer. Detect the change in encoding->data. */ -static UA_StatusCode - detectValueChange(UA_Server *server, UA_Session *session, UA_MonitoredItem *mon, - UA_DataValue value, UA_ByteString *encoding, UA_Boolean *changed) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_assert(trigger == UA_DATACHANGETRIGGER_STATUSVALUE || + trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP); - /* Apply Filter */ - if(mon->filter.dataChangeFilter.trigger == UA_DATACHANGETRIGGER_STATUS) - value.hasValue = false; + /* Test absolute deadband */ + if(dcf && dcf->deadbandType == UA_DEADBANDTYPE_ABSOLUTE && + value->value.type != NULL && UA_DataType_isNumeric(value->value.type)) + return detectVariantDeadband(&value->value, &mon->lastValue.value, + dcf->deadbandValue); - value.hasServerTimestamp = false; - value.hasServerPicoseconds = false; - if(mon->filter.dataChangeFilter.trigger < UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP) { - value.hasSourceTimestamp = false; - value.hasSourcePicoseconds = false; + /* Compare the source timestamp if the trigger requires that */ + if(trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP) { + if(value->hasSourceTimestamp != mon->lastValue.hasSourceTimestamp) + return true; + if(value->hasSourceTimestamp && + value->sourceTimestamp != mon->lastValue.sourceTimestamp) + return true; } - /* Detect the value change */ - return detectValueChangeWithFilter(server, session, mon, &value, encoding, changed); + /* Has the value changed? */ + if(value->hasValue != mon->lastValue.hasValue) + return true; + return (UA_order(&value->value, &mon->lastValue.value, + &UA_TYPES[UA_TYPES_VARIANT]) != UA_ORDER_EQ); } -/* movedValue returns whether the sample was moved to the notification. The - * default is false. */ -static UA_StatusCode -sampleCallbackWithValue(UA_Server *server, UA_Session *session, - UA_Subscription *sub, UA_MonitoredItem *mon, - UA_DataValue *value, UA_Boolean *movedValue) { - UA_assert(mon->attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER); - - /* Contains heap-allocated binary encoding of the value if a change was detected */ - UA_ByteString binValueEncoding = UA_BYTESTRING_NULL; +UA_StatusCode +UA_MonitoredItem_createDataChangeNotification(UA_Server *server, UA_Subscription *sub, + UA_MonitoredItem *mon, + const UA_DataValue *value) { + /* Allocate a new notification */ + UA_Notification *newNotification = UA_Notification_new(); + if(!newNotification) + return UA_STATUSCODE_BADOUTOFMEMORY; - /* Has the value changed? Allocates memory in binValueEncoding if necessary. - * value is edited internally so we make a shallow copy. */ - UA_Boolean changed = false; - UA_StatusCode retval = detectValueChange(server, session, mon, *value, &binValueEncoding, &changed); + /* Prepare the notification */ + newNotification->mon = mon; + newNotification->data.dataChange.clientHandle = mon->parameters.clientHandle; + UA_StatusCode retval = UA_DataValue_copy(value, &newNotification->data.dataChange.value); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_SESSION(&server->config.logger, session, "Subscription %" PRIu32 " | " - "MonitoredItem %" PRIi32 " | Value change detection failed with StatusCode %s", - sub ? sub->subscriptionId : 0, mon->monitoredItemId, - UA_StatusCode_name(retval)); + UA_free(newNotification); return retval; } + + /* Enqueue the notification */ + UA_assert(sub); + UA_Notification_enqueueAndTrigger(server, newNotification); + return UA_STATUSCODE_GOOD; +} + +/* Moves the value to the MonitoredItem if successful */ +UA_StatusCode +sampleCallbackWithValue(UA_Server *server, UA_Subscription *sub, + UA_MonitoredItem *mon, UA_DataValue *value) { + UA_assert(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER); + + /* Has the value changed (with the filters applied)? */ + UA_Boolean changed = detectValueChange(server, mon, value); if(!changed) { - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Subscription %" PRIu32 " | " - "MonitoredItem %" PRIi32 " | The value has not changed", - sub ? sub->subscriptionId : 0, mon->monitoredItemId); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %" PRIi32 " | " + "The value has not changed", mon->monitoredItemId); + UA_DataValue_clear(value); return UA_STATUSCODE_GOOD; } /* The MonitoredItem is attached to a subscription (not server-local). * Prepare a notification and enqueue it. */ if(sub) { - /* Allocate a new notification */ - UA_Notification *newNotification = (UA_Notification *)UA_malloc(sizeof(UA_Notification)); - if(!newNotification) { - UA_ByteString_clear(&binValueEncoding); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - - if(value->value.storageType == UA_VARIANT_DATA) { - newNotification->data.value = *value; /* Move the value to the notification */ - *movedValue = true; - } else { /* => (value->value.storageType == UA_VARIANT_DATA_NODELETE) */ - retval = UA_DataValue_copy(value, &newNotification->data.value); - if(retval != UA_STATUSCODE_GOOD) { - UA_ByteString_clear(&binValueEncoding); - UA_free(newNotification); - return retval; - } - } - - /* <-- Point of no return --> */ - - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Subscription %" PRIu32 " | " - "MonitoredItem %" PRIi32 " | Enqueue a new notification", - sub ? sub->subscriptionId : 0, mon->monitoredItemId); - - newNotification->mon = mon; - UA_Notification_enqueue(server, sub, mon, newNotification); + UA_StatusCode retval = + UA_MonitoredItem_createDataChangeNotification(server, sub, mon, value); + if(retval != UA_STATUSCODE_GOOD) + return retval; } - /* Store the encoding for comparison */ - UA_ByteString_clear(&mon->lastSampledValue); - mon->lastSampledValue = binValueEncoding; + /* <-- Point of no return --> */ - /* Store the value for filter comparison (we don't want to decode - * lastSampledValue in every iteration). Don't test the return code here. If - * this fails, lastValue is empty and a notification will be forced for the - * next deadband comparison. */ - if((mon->filter.dataChangeFilter.deadbandType == UA_DEADBANDTYPE_NONE || - mon->filter.dataChangeFilter.deadbandType == UA_DEADBANDTYPE_ABSOLUTE || - mon->filter.dataChangeFilter.deadbandType == UA_DEADBANDTYPE_PERCENT) && - (mon->filter.dataChangeFilter.trigger == UA_DATACHANGETRIGGER_STATUS || - mon->filter.dataChangeFilter.trigger == UA_DATACHANGETRIGGER_STATUSVALUE || - mon->filter.dataChangeFilter.trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP)) { - UA_Variant_clear(&mon->lastValue); - UA_Variant_copy(&value->value, &mon->lastValue); -#ifdef UA_ENABLE_DA - mon->lastStatus = value->status; -#endif - } + /* Move/store the value for filter comparison and TransferSubscription */ + UA_DataValue_clear(&mon->lastValue); + mon->lastValue = *value; /* Call the local callback if the MonitoredItem is not attached to a * subscription. Do this at the very end. Because the callback might delete @@ -54681,121 +60188,73 @@ sampleCallbackWithValue(UA_Server *server, UA_Session *session, if(!sub) { UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*) mon; void *nodeContext = NULL; - getNodeContext(server, mon->monitoredNodeId, &nodeContext); - UA_UNLOCK(server->serviceMutex); - localMon->callback.dataChangeCallback(server, mon->monitoredItemId, - localMon->context, - &mon->monitoredNodeId, - nodeContext, mon->attributeId, - value); - UA_LOCK(server->serviceMutex); + getNodeContext(server, mon->itemToMonitor.nodeId, &nodeContext); + UA_UNLOCK(&server->serviceMutex); + localMon->callback.dataChangeCallback(server, + mon->monitoredItemId, localMon->context, + &mon->itemToMonitor.nodeId, nodeContext, + mon->itemToMonitor.attributeId, value); + UA_LOCK(&server->serviceMutex); } return UA_STATUSCODE_GOOD; } void -UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem) -{ - UA_LOCK(server->serviceMutex); +UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem) { + UA_LOCK(&server->serviceMutex); monitoredItem_sampleCallback(server, monitoredItem); - UA_UNLOCK(server->serviceMutex) + UA_UNLOCK(&server->serviceMutex); } void monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem) { - UA_LOCK_ASSERT(server->serviceMutex, 1); + UA_LOCK_ASSERT(&server->serviceMutex, 1); UA_Subscription *sub = monitoredItem->subscription; UA_Session *session = &server->adminSession; if(sub) session = sub->session; - UA_LOG_DEBUG_SESSION(&server->config.logger, session, "Subscription %" PRIu32 " | " - "MonitoredItem %" PRIi32 " | Sample callback called", - sub ? sub->subscriptionId : 0, monitoredItem->monitoredItemId); - - UA_assert(monitoredItem->attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER); + UA_LOG_DEBUG_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %" PRIi32 " | " + "Sample callback called", monitoredItem->monitoredItemId); - /* Get the node */ - const UA_Node *node = UA_NODESTORE_GET(server, &monitoredItem->monitoredNodeId); + UA_assert(monitoredItem->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER); /* Sample the value. The sample can still point into the node. */ - UA_DataValue value; - UA_DataValue_init(&value); - if(node) { - UA_ReadValueId rvid; - UA_ReadValueId_init(&rvid); - rvid.nodeId = monitoredItem->monitoredNodeId; - rvid.attributeId = monitoredItem->attributeId; - rvid.indexRange = monitoredItem->indexRange; - ReadWithNode(node, server, session, monitoredItem->timestampsToReturn, &rvid, &value); - } else { - value.hasStatus = true; - value.status = UA_STATUSCODE_BADNODEIDUNKNOWN; - } + UA_DataValue value = UA_Server_readWithSession(server, session, + &monitoredItem->itemToMonitor, + monitoredItem->timestampsToReturn); - /* Operate on the sample */ - UA_Boolean movedValue = false; - UA_StatusCode retval = sampleCallbackWithValue(server, session, sub, monitoredItem, &value, &movedValue); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING_SESSION(&server->config.logger, session, "Subscription %" PRIu32 " | " - "MonitoredItem %" PRIi32 " | Sampling returned the statuscode %s", - sub ? sub->subscriptionId : 0, monitoredItem->monitoredItemId, - UA_StatusCode_name(retval)); + /* Operate on the sample. The sample is consumed when the status is good. */ + UA_StatusCode res = sampleCallbackWithValue(server, sub, monitoredItem, &value); + if(res != UA_STATUSCODE_GOOD) { + UA_DataValue_clear(&value); + UA_LOG_WARNING_SUBSCRIPTION(&server->config.logger, sub, + "MonitoredItem %" PRIi32 " | " + "Sampling returned the statuscode %s", + monitoredItem->monitoredItemId, + UA_StatusCode_name(res)); } - - /* Delete the sample if it was not moved to the notification. */ - if(!movedValue) - UA_DataValue_clear(&value); /* Does nothing for UA_VARIANT_DATA_NODELETE */ - if(node) - UA_NODESTORE_RELEASE(server, node); } #endif /* UA_ENABLE_SUBSCRIPTIONS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/src/server/ua_subscription_events.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_subscription_events.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH - * Copyright 2020 (c) Christian von Arnim + * Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + * Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner) */ #ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS -UA_StatusCode -UA_MonitoredItem_removeNodeEventCallback(UA_Server *server, UA_Session *session, - UA_Node *node, void *data) { - if (node->nodeClass != UA_NODECLASS_OBJECT) - return UA_STATUSCODE_BADINVALIDARGUMENT; - UA_ObjectNode *on = (UA_ObjectNode*)node; - UA_MonitoredItem *remove = (UA_MonitoredItem*)data; - - if(!on->monitoredItemQueue) - return UA_STATUSCODE_GOOD; - - /* Edge case that it's the first element */ - if(on->monitoredItemQueue == remove) { - on->monitoredItemQueue = remove->next; - return UA_STATUSCODE_GOOD; - } - - UA_MonitoredItem *prev = on->monitoredItemQueue; - UA_MonitoredItem *entry = prev->next; - for(; entry != NULL; prev = entry, entry = entry->next) { - if(entry == remove) { - prev->next = entry->next; - return UA_STATUSCODE_GOOD; - } - } - - return UA_STATUSCODE_BADNOTFOUND; -} - /* We use a 16-Byte ByteString as an identifier */ UA_StatusCode UA_Event_generateEventId(UA_ByteString *generatedId) { @@ -54815,28 +60274,28 @@ UA_Event_generateEventId(UA_ByteString *generatedId) { UA_StatusCode UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *outNodeId) { - UA_LOCK(server->serviceMutex); + UA_LOCK(&server->serviceMutex); if(!outNodeId) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND, "outNodeId must not be NULL. The event's NodeId must be returned " "so it can be triggered."); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINVALIDARGUMENT; } /* Make sure the eventType is a subtype of BaseEventType */ - UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); - if(!isNodeInTree(server, &eventType, &baseEventTypeId, &hasSubtypeId, 1)) { + if(!isNodeInTree_singleRef(server, &eventType, &baseEventTypeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Event type must be a subtype of BaseEventType!"); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_BADINVALIDARGUMENT; } /* Create an ObjectNode which represents the event */ UA_QualifiedName name; - // set a dummy name. This is not used. + /* set a dummy name. This is not used. */ name = UA_QUALIFIEDNAME(0,"E"); UA_NodeId newNodeId = UA_NODEID_NULL; UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; @@ -54853,6 +60312,7 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, if(retval != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Adding event failed. StatusCode %s", UA_StatusCode_name(retval)); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -54864,7 +60324,7 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_BrowsePathResult_clear(&bpr); deleteNode(server, newNodeId, true); UA_NodeId_clear(&newNodeId); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } @@ -54872,311 +60332,18 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType, UA_Variant value; UA_Variant_init(&value); UA_Variant_setScalar(&value, (void*)(uintptr_t)&eventType, &UA_TYPES[UA_TYPES_NODEID]); - retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); + retval = writeValueAttribute(server, &server->adminSession, + &bpr.targets[0].targetId.nodeId, &value); UA_BrowsePathResult_clear(&bpr); if(retval != UA_STATUSCODE_GOOD) { deleteNode(server, newNodeId, true); UA_NodeId_clear(&newNodeId); - UA_UNLOCK(server->serviceMutex); + UA_UNLOCK(&server->serviceMutex); return retval; } *outNodeId = newNodeId; - UA_UNLOCK(server->serviceMutex); - return UA_STATUSCODE_GOOD; -} - -static UA_Boolean -isValidEvent(UA_Server *server, const UA_NodeId *validEventParent, - const UA_NodeId *eventId) { - /* find the eventType variableNode */ - UA_QualifiedName findName = UA_QUALIFIEDNAME(0, "EventType"); - UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, *eventId, 1, &findName); - if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) { - UA_BrowsePathResult_clear(&bpr); - return false; - } - - /* Get the EventType Property Node */ - UA_Variant tOutVariant; - UA_Variant_init(&tOutVariant); - - /* Read the Value of EventType Property Node (the Value should be a NodeId) */ - UA_StatusCode retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId, - UA_ATTRIBUTEID_VALUE, &tOutVariant); - if(retval != UA_STATUSCODE_GOOD || - !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_NODEID])) { - UA_BrowsePathResult_clear(&bpr); - return false; - } - - const UA_NodeId *tEventType = (UA_NodeId*)tOutVariant.data; - - /* check whether the EventType is a Subtype of CondtionType - * (Part 9 first implementation) */ - UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE); - UA_NodeId hasSubtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); - - if(UA_NodeId_equal(validEventParent, &conditionTypeId) && - isNodeInTree(server, tEventType, - &conditionTypeId, &hasSubtypeId, 1)){ - UA_BrowsePathResult_deleteMembers(&bpr); - UA_Variant_clear(&tOutVariant); - return true; - } - - /*EventType is not a Subtype of CondtionType - *(ConditionId Clause won't be present in Events, which are not Conditions)*/ - /* check whether Valid Event other than Conditions */ - UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); - UA_Boolean isSubtypeOfBaseEvent = isNodeInTree(server, tEventType, - &baseEventTypeId, &hasSubtypeId, 1); - - UA_BrowsePathResult_clear(&bpr); - UA_Variant_clear(&tOutVariant); - return isSubtypeOfBaseEvent; -} - -/* Part 4: 7.4.4.5 SimpleAttributeOperand - * The clause can point to any attribute of nodes. Either a child of the event - * node and also the event type. */ -static UA_StatusCode -resolveSimpleAttributeOperand(UA_Server *server, UA_Session *session, const UA_NodeId *origin, - const UA_SimpleAttributeOperand *sao, UA_Variant *value) { - /* Prepare the ReadValueId */ - UA_ReadValueId rvi; - UA_ReadValueId_init(&rvi); - rvi.indexRange = sao->indexRange; - rvi.attributeId = sao->attributeId; - - /* If this list (browsePath) is empty the Node is the instance of the - * TypeDefinition. */ - if(sao->browsePathSize == 0) { - UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE); - -#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS - //TODO check for Branches! One Condition could have multiple Branches - // Set ConditionId - if(UA_NodeId_equal(&sao->typeDefinitionId, &conditionTypeId)){ - UA_NodeId conditionId; - UA_StatusCode retval = UA_getConditionId(server, origin, &conditionId); - if(retval != UA_STATUSCODE_GOOD) - return retval; - - rvi.nodeId = conditionId; - } - else - rvi.nodeId = sao->typeDefinitionId; -#else - if(UA_NodeId_equal(&sao->typeDefinitionId, &conditionTypeId)) - return UA_STATUSCODE_BADNOTSUPPORTED; - else - rvi.nodeId = sao->typeDefinitionId; -#endif /*UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS*/ - UA_DataValue v = UA_Server_readWithSession(server, session, &rvi, - UA_TIMESTAMPSTORETURN_NEITHER); - if(v.status == UA_STATUSCODE_GOOD && v.hasValue) - *value = v.value; - return v.status; - } - - /* Resolve the browse path */ - UA_BrowsePathResult bpr = - browseSimplifiedBrowsePath(server, *origin, sao->browsePathSize, sao->browsePath); - if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD) - bpr.statusCode = UA_STATUSCODE_BADNOTFOUND; - if(bpr.statusCode != UA_STATUSCODE_GOOD) { - UA_StatusCode retval = bpr.statusCode; - UA_BrowsePathResult_clear(&bpr); - return retval; - } - - /* Read the first matching element. Move the value to the output. */ - rvi.nodeId = bpr.targets[0].targetId.nodeId; - UA_DataValue v = UA_Server_readWithSession(server, session, &rvi, - UA_TIMESTAMPSTORETURN_NEITHER); - if(v.status == UA_STATUSCODE_GOOD && v.hasValue) - *value = v.value; - - UA_BrowsePathResult_clear(&bpr); - return v.status; -} - -UA_StatusCode -UA_Server_evaluateWhereClauseContentFilter( - UA_Server *server, - const UA_NodeId *eventNode, - const UA_ContentFilter *contentFilter) { - if(contentFilter->elements == NULL || contentFilter->elementsSize == 0) - { - /* Nothing to do.*/ - /** @todo Whats the default result?*/ - return UA_STATUSCODE_GOOD; - } - - /* The first element needs to be evaluated, this might be linked to */ - /* other elements, which are evaluated in these cases.*/ - /* See 7.4.1 in Part 4, v1.04-Nov 22, 2017 */ - UA_ContentFilterElement *pElement = &contentFilter->elements[0]; - /** @todo Verify retun types in specification or CTT */ - switch (pElement->filterOperator) - { - case UA_FILTEROPERATOR_INVIEW: - case UA_FILTEROPERATOR_RELATEDTO: - { - /*Not allowed for event WhereClause according to 7.17.3 in */ - /* Part 4, v1.04-Nov 22, 2017*/ - return UA_STATUSCODE_BADEVENTFILTERINVALID; - } - case UA_FILTEROPERATOR_EQUALS: - case UA_FILTEROPERATOR_ISNULL: - case UA_FILTEROPERATOR_GREATERTHAN: - case UA_FILTEROPERATOR_LESSTHAN: - case UA_FILTEROPERATOR_GREATERTHANOREQUAL: - case UA_FILTEROPERATOR_LESSTHANOREQUAL: - case UA_FILTEROPERATOR_LIKE: - case UA_FILTEROPERATOR_NOT: - case UA_FILTEROPERATOR_BETWEEN: - case UA_FILTEROPERATOR_INLIST: - case UA_FILTEROPERATOR_AND: - case UA_FILTEROPERATOR_OR: - case UA_FILTEROPERATOR_CAST: - case UA_FILTEROPERATOR_BITWISEAND: - case UA_FILTEROPERATOR_BITWISEOR: - { - return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; - } - case UA_FILTEROPERATOR_OFTYPE: - { - UA_Boolean result = UA_FALSE; - if(pElement->filterOperandsSize != 1) - { - return UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; - } - if(pElement->filterOperands[0].content.decoded.type != - &UA_TYPES[UA_TYPES_LITERALOPERAND]) - { - return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; - } - UA_LiteralOperand *pOperand = - (UA_LiteralOperand *) pElement->filterOperands[0].content.decoded.data; - if(!UA_Variant_isScalar(&pOperand->value)) - { - return UA_STATUSCODE_BADEVENTFILTERINVALID; - } - - if(pOperand->value.type != &UA_TYPES[UA_TYPES_NODEID] - || pOperand->value.data == NULL) - { - result = UA_FALSE; - } - else { - UA_NodeId *pOperandNodeId = (UA_NodeId *) pOperand->value.data; - UA_NodeId hasSubtypeId = - UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); - UA_QualifiedName eventTypeQualifiedName = - UA_QUALIFIEDNAME(0, "EventType"); - UA_Variant typeNodeIdVariant; - UA_Variant_init(&typeNodeIdVariant); - UA_StatusCode readStatusCode = - readObjectProperty( - server, *eventNode, - eventTypeQualifiedName, &typeNodeIdVariant); - if(readStatusCode != UA_STATUSCODE_GOOD) - { - return readStatusCode; - } - - if(!UA_Variant_isScalar(&typeNodeIdVariant) - || typeNodeIdVariant.type != &UA_TYPES[UA_TYPES_NODEID] - || typeNodeIdVariant.data == NULL) - { - UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, - "EventType has an invalid type."); - UA_Variant_clear(&typeNodeIdVariant); - return UA_STATUSCODE_BADINTERNALERROR; - } - result = isNodeInTree( - server, (UA_NodeId*) typeNodeIdVariant.data, - pOperandNodeId, &hasSubtypeId, 1); - UA_Variant_clear(&typeNodeIdVariant); - } - - if(result) - { - return UA_STATUSCODE_GOOD; - } - else - { - return UA_STATUSCODE_BADNOMATCH; - } - } - break; - default: - return UA_STATUSCODE_BADFILTEROPERATORINVALID; - break; - } -} - -/* Filters the given event with the given filter and writes the results into a - * notification */ -static UA_StatusCode -UA_Server_filterEvent(UA_Server *server, UA_Session *session, - const UA_NodeId *eventNode, UA_EventFilter *filter, - UA_EventNotification *notification) { - if (filter->selectClausesSize == 0) - return UA_STATUSCODE_BADEVENTFILTERINVALID; - - UA_StatusCode retVal = UA_Server_evaluateWhereClauseContentFilter( - server, eventNode, &filter->whereClause); - if(retVal != UA_STATUSCODE_GOOD) - { - return retVal; - } - UA_EventFieldList_init(¬ification->fields); - /* EventFilterResult isn't being used currently - UA_EventFilterResult_init(¬ification->result); */ - - notification->fields.eventFields = (UA_Variant *) - UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_VARIANT]); - if(!notification->fields.eventFields) { - /* EventFilterResult currently isn't being used - UA_EventFiterResult_clear(¬ification->result); */ - return UA_STATUSCODE_BADOUTOFMEMORY; - } - notification->fields.eventFieldsSize = filter->selectClausesSize; - - /* EventFilterResult currently isn't being used - notification->result.selectClauseResultsSize = filter->selectClausesSize; - notification->result.selectClauseResults = (UA_StatusCode *) - UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_STATUSCODE]); - if(!notification->result->selectClauseResults) { - UA_EventFieldList_clear(¬ification->fields); - UA_EventFilterResult_clear(¬ification->result); - return UA_STATUSCODE_BADOUTOFMEMORY; - } - */ - - /* Apply the filter */ - - /* Check if the browsePath is BaseEventType, in which case nothing more - * needs to be checked */ - UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); - for(size_t i = 0; i < filter->selectClausesSize; i++) { - if(!UA_NodeId_equal(&filter->selectClauses[i].typeDefinitionId, &baseEventTypeId) && - !isValidEvent(server, &filter->selectClauses[i].typeDefinitionId, eventNode)) { - UA_Variant_init(¬ification->fields.eventFields[i]); - /* EventFilterResult currently isn't being used - notification->result.selectClauseResults[i] = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; */ - continue; - } - - /* TODO: Put the result into the selectClausResults */ - resolveSimpleAttributeOperand(server, session, eventNode, - &filter->selectClauses[i], - ¬ification->fields.eventFields[i]); - } - + UA_UNLOCK(&server->serviceMutex); return UA_STATUSCODE_GOOD; } @@ -55195,8 +60362,8 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event, UA_Variant value; UA_Variant_init(&value); UA_Variant_setScalarCopy(&value, origin, &UA_TYPES[UA_TYPES_NODEID]); - retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, - UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); + retval = writeValueAttribute(server, &server->adminSession, + &bpr.targets[0].targetId.nodeId, &value); UA_Variant_clear(&value); UA_BrowsePathResult_clear(&bpr); if(retval != UA_STATUSCODE_GOOD) @@ -55212,8 +60379,8 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event, } UA_DateTime rcvTime = UA_DateTime_now(); UA_Variant_setScalar(&value, &rcvTime, &UA_TYPES[UA_TYPES_DATETIME]); - retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, - UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); + retval = writeValueAttribute(server, &server->adminSession, + &bpr.targets[0].targetId.nodeId, &value); UA_BrowsePathResult_clear(&bpr); if(retval != UA_STATUSCODE_GOOD) return retval; @@ -55233,8 +60400,8 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event, } UA_Variant_init(&value); UA_Variant_setScalar(&value, &eventId, &UA_TYPES[UA_TYPES_BYTESTRING]); - retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, - UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); + retval = writeValueAttribute(server, &server->adminSession, + &bpr.targets[0].targetId.nodeId, &value); UA_BrowsePathResult_clear(&bpr); if(retval != UA_STATUSCODE_GOOD) { UA_ByteString_clear(&eventId); @@ -55253,36 +60420,88 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event, /* Filters an event according to the filter specified by mon and then adds it to * mons notification queue */ UA_StatusCode -UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event, UA_MonitoredItem *mon) { - UA_Notification *notification = (UA_Notification *) UA_malloc(sizeof(UA_Notification)); +UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event, + UA_MonitoredItem *mon) { + UA_Notification *notification = UA_Notification_new(); if(!notification) return UA_STATUSCODE_BADOUTOFMEMORY; - /* Get the session */ - UA_Subscription *sub = mon->subscription; - UA_Session *session = sub->session; + if(mon->parameters.filter.content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER]) + return UA_STATUSCODE_BADFILTERNOTALLOWED; + UA_EventFilter *eventFilter = (UA_EventFilter*) + mon->parameters.filter.content.decoded.data; + /* The MonitoredItem must be attached to a Subscription. This code path is + * not taken for local MonitoredItems (once they are enabled for Events). */ + UA_Subscription *sub = mon->subscription; + UA_assert(sub); - /* Apply the filter */ - UA_StatusCode retval = - UA_Server_filterEvent(server, session, event, &mon->filter.eventFilter, - ¬ification->data.event); - if(retval == UA_STATUSCODE_BADNOMATCH) - { - UA_free(notification); - return UA_STATUSCODE_GOOD; - } + UA_Session *session = sub->session; + UA_StatusCode retval = filterEvent(server, session, event, + eventFilter, ¬ification->data.event, + ¬ification->result); if(retval != UA_STATUSCODE_GOOD) { - UA_free(notification); + UA_Notification_delete(notification); + if(retval == UA_STATUSCODE_BADNOMATCH) + return UA_STATUSCODE_GOOD; return retval; } - /* Enqueue the notification */ + notification->data.event.clientHandle = mon->parameters.clientHandle; notification->mon = mon; - UA_Notification_enqueue(server, mon->subscription, mon, notification); + + UA_Notification_enqueueAndTrigger(server, notification); return UA_STATUSCODE_GOOD; } +#ifdef UA_ENABLE_HISTORIZING +static void +setHistoricalEvent(UA_Server *server, const UA_NodeId *origin, + const UA_NodeId *emitNodeId, const UA_NodeId *eventNodeId) { + UA_Variant historicalEventFilterValue; + UA_Variant_init(&historicalEventFilterValue); + + /* A HistoricalEventNode that has event history available will provide this property */ + UA_StatusCode retval = + readObjectProperty(server, *emitNodeId, + UA_QUALIFIEDNAME(0, "HistoricalEventFilter"), + &historicalEventFilterValue); + if(retval != UA_STATUSCODE_GOOD) { + /* Do not vex users with no match errors */ + if(retval != UA_STATUSCODE_BADNOMATCH) + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Cannot read the HistoricalEventFilter property of a " + "listening node. StatusCode %s", + UA_StatusCode_name(retval)); + return; + } + + /* If found then check if HistoricalEventFilter property has a valid value */ + if(UA_Variant_isEmpty(&historicalEventFilterValue) || + !UA_Variant_isScalar(&historicalEventFilterValue) || + historicalEventFilterValue.type != &UA_TYPES[UA_TYPES_EVENTFILTER]) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "HistoricalEventFilter property of a listening node " + "does not have a valid value"); + UA_Variant_clear(&historicalEventFilterValue); + return; + } + + /* Finally, if found and valid then filter */ + UA_EventFilter *filter = (UA_EventFilter*) historicalEventFilterValue.data; + UA_EventFieldList efl; + UA_EventFilterResult result; + retval = filterEvent(server, &server->adminSession, + eventNodeId, filter, &efl, &result); + if(retval == UA_STATUSCODE_GOOD) + server->config.historyDatabase.setEvent(server, server->config.historyDatabase.context, + origin, emitNodeId, filter, &efl); + UA_EventFilterResult_clear(&result); + UA_Variant_clear(&historicalEventFilterValue); + UA_EventFieldList_clear(&efl); +} +#endif + static const UA_NodeId objectsFolderId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_OBJECTSFOLDER}}; #define EMIT_REFS_ROOT_COUNT 4 static const UA_NodeId emitReferencesRoots[EMIT_REFS_ROOT_COUNT] = @@ -55291,18 +60510,20 @@ static const UA_NodeId emitReferencesRoots[EMIT_REFS_ROOT_COUNT] = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASEVENTSOURCE}}, {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASNOTIFIER}}}; +static const UA_NodeId isInFolderReferences[2] = + {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}}, + {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}}; + UA_StatusCode -UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, - const UA_NodeId origin, UA_ByteString *outEventId, - const UA_Boolean deleteEventNode) { - UA_LOCK(server->serviceMutex); +triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, + const UA_NodeId origin, UA_ByteString *outEventId, + const UA_Boolean deleteEventNode) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); -#if UA_LOGLEVEL <= 200 - UA_LOG_NODEID_WRAP(&origin, - UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Events: An event is triggered on node %.*s", - (int)nodeIdStr.length, nodeIdStr.data)); -#endif + UA_LOG_NODEID_DEBUG(&origin, + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Events: An event is triggered on node %.*s", + (int)nodeIdStr.length, nodeIdStr.data)); #ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS UA_Boolean isCallerAC = false; @@ -55311,40 +60532,48 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Condition Events: Please use A&C API to trigger Condition Events 0x%08X", UA_STATUSCODE_BADINVALIDARGUMENT); - UA_UNLOCK(server->serviceMutex); return UA_STATUSCODE_BADINVALIDARGUMENT; } } -#endif /*UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS*/ +#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ /* Check that the origin node exists */ const UA_Node *originNode = UA_NODESTORE_GET(server, &origin); if(!originNode) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Origin node for event does not exist."); - UA_UNLOCK(server->serviceMutex); return UA_STATUSCODE_BADNOTFOUND; } UA_NODESTORE_RELEASE(server, originNode); /* Make sure the origin is in the ObjectsFolder (TODO: or in the ViewsFolder) */ - if(!isNodeInTree(server, &origin, &objectsFolderId, - emitReferencesRoots, 2)) { /* Only use Organizes and - * HasComponent to check if we - * are below the ObjectsFolder */ + /* Only use Organizes and HasComponent to check if we are below the ObjectsFolder */ + UA_StatusCode retval; + UA_ReferenceTypeSet refTypes; + UA_ReferenceTypeSet_init(&refTypes); + for(int i = 0; i < 2; ++i) { + UA_ReferenceTypeSet tmpRefTypes; + retval = referenceTypeIndices(server, &isInFolderReferences[i], &tmpRefTypes, true); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Events: Could not create the list of references and their subtypes " + "with StatusCode %s", UA_StatusCode_name(retval)); + } + refTypes = UA_ReferenceTypeSet_union(refTypes, tmpRefTypes); + } + + if(!isNodeInTree(server, &origin, &objectsFolderId, &refTypes)) { UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Node for event must be in ObjectsFolder!"); - UA_UNLOCK(server->serviceMutex); return UA_STATUSCODE_BADINVALIDARGUMENT; } /* Update the standard fields of the event */ - UA_StatusCode retval = eventSetStandardFields(server, &eventNodeId, &origin, outEventId); + retval = eventSetStandardFields(server, &eventNodeId, &origin, outEventId); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Events: Could not set the standard event fields with StatusCode %s", UA_StatusCode_name(retval)); - UA_UNLOCK(server->serviceMutex); return retval; } @@ -55365,34 +60594,23 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, emitStartNodes[1] = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER); /* Get all ReferenceTypes over which the events propagate */ - UA_NodeId *emitRefTypes[EMIT_REFS_ROOT_COUNT] = {NULL, NULL, NULL}; - size_t emitRefTypesSize[EMIT_REFS_ROOT_COUNT] = {0, 0, 0, 0}; - size_t totalEmitRefTypesSize = 0; - for (size_t i=0; i<EMIT_REFS_ROOT_COUNT; i++) { - retval |= referenceSubtypes(server, &emitReferencesRoots[i], - &emitRefTypesSize[i], &emitRefTypes[i]); - totalEmitRefTypesSize += emitRefTypesSize[i]; - } - UA_STACKARRAY(UA_NodeId, totalEmitRefTypes, totalEmitRefTypesSize); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Events: Could not create the list of references for event " - "propagation with StatusCode %s", UA_StatusCode_name(retval)); - goto cleanup; - } - - size_t currIndex = 0; - for (size_t i=0; i<EMIT_REFS_ROOT_COUNT; i++) { - memcpy(&totalEmitRefTypes[currIndex], emitRefTypes[i], - emitRefTypesSize[i] * sizeof(UA_NodeId)); - currIndex += emitRefTypesSize[i]; + UA_ReferenceTypeSet emitRefTypes; + UA_ReferenceTypeSet_init(&emitRefTypes); + for(size_t i = 0; i < EMIT_REFS_ROOT_COUNT; i++) { + UA_ReferenceTypeSet tmpRefTypes; + retval = referenceTypeIndices(server, &emitReferencesRoots[i], &tmpRefTypes, true); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Events: Could not create the list of references for event " + "propagation with StatusCode %s", UA_StatusCode_name(retval)); + goto cleanup; + } + emitRefTypes = UA_ReferenceTypeSet_union(emitRefTypes, tmpRefTypes); } - /* Get the list of nodes in the hierarchy that emits the event. */ - retval = browseRecursive(server, 2, emitStartNodes, - totalEmitRefTypesSize, totalEmitRefTypes, - UA_BROWSEDIRECTION_INVERSE, true, + retval = browseRecursive(server, 2, emitStartNodes, UA_BROWSEDIRECTION_INVERSE, + &emitRefTypes, UA_NODECLASS_UNSPECIFIED, true, &emitNodesSize, &emitNodes); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, @@ -55403,74 +60621,37 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, /* Add the event to the listening MonitoredItems at each relevant node */ for(size_t i = 0; i < emitNodesSize; i++) { - const UA_ObjectNode *node = (const UA_ObjectNode*) - UA_NODESTORE_GET(server, &emitNodes[i].nodeId); + /* Get the node */ + const UA_Node *node = UA_NODESTORE_GET(server, &emitNodes[i].nodeId); if(!node) continue; - if(node->nodeClass != UA_NODECLASS_OBJECT) { - UA_NODESTORE_RELEASE(server, (const UA_Node*)node); + + /* Only consider objects */ + if(node->head.nodeClass != UA_NODECLASS_OBJECT) { + UA_NODESTORE_RELEASE(server, node); continue; } - for(UA_MonitoredItem *mi = node->monitoredItemQueue; mi != NULL; mi = mi->next) { - retval = UA_Event_addEventToMonitoredItem(server, &eventNodeId, mi); + + /* Add event to monitoreditems */ + for(UA_MonitoredItem *mon = node->head.monitoredItems; mon != NULL; mon = mon->next) { + /* Is this an Event-MonitoredItem? */ + if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) + continue; + retval = UA_Event_addEventToMonitoredItem(server, &eventNodeId, mon); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Events: Could not add the event to a listening node with StatusCode %s", - UA_StatusCode_name(retval)); + "Events: Could not add the event to a listening " + "node with StatusCode %s", UA_StatusCode_name(retval)); retval = UA_STATUSCODE_GOOD; /* Only log problems with individual emit nodes */ } } - UA_NODESTORE_RELEASE(server, (const UA_Node*)node); + + UA_NODESTORE_RELEASE(server, node); + + /* Add event entry in the historical database */ #ifdef UA_ENABLE_HISTORIZING - if(!server->config.historyDatabase.setEvent) - continue; - UA_EventFilter *filter = NULL; - UA_EventFieldList *fieldList = NULL; - UA_Variant historicalEventFilterValue; - UA_Variant_init(&historicalEventFilterValue); - /* a HistoricalEventNode that has event history available will provide this property */ - retval = readObjectProperty(server, emitNodes[i].nodeId, - UA_QUALIFIEDNAME(0, "HistoricalEventFilter"), - &historicalEventFilterValue); - /* check if the property was found and the read was successful */ - if(retval != UA_STATUSCODE_GOOD) { - /* do not vex users with no match errors */ - if(retval != UA_STATUSCODE_BADNOMATCH) - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "Cannot read the HistoricalEventFilter property of a " - "listening node. StatusCode %s", - UA_StatusCode_name(retval)); - } - /* if found then check if HistoricalEventFilter property has a valid value */ - else if(UA_Variant_isEmpty(&historicalEventFilterValue) || - !UA_Variant_isScalar(&historicalEventFilterValue) || - historicalEventFilterValue.type->typeIndex != UA_TYPES_EVENTFILTER) { - UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, - "HistoricalEventFilter property of a listening node " - "does not have a valid value"); - } - /* finally, if found and valid then filter */ - else { - filter = (UA_EventFilter*)historicalEventFilterValue.data; - UA_EventNotification eventNotification; - retval = UA_Server_filterEvent(server, &server->adminSession, &eventNodeId, - filter, &eventNotification); - if(retval == UA_STATUSCODE_GOOD) { - fieldList = UA_EventFieldList_new(); - *fieldList = eventNotification.fields; - } - /* eventNotification structure is not cleared so that users can - * avoid copying the field list if they want to store it */ - /* EventFilterResult isn't being used currently - UA_EventFilterResult_clear(¬ification->result); */ - } - server->config.historyDatabase.setEvent(server, server->config.historyDatabase.context, - &origin, &emitNodes[i].nodeId, - &eventNodeId, deleteEventNode, - filter, - fieldList); - UA_Variant_clear(&historicalEventFilterValue); - retval = UA_STATUSCODE_GOOD; + if(server->config.historyDatabase.setEvent) + setHistoricalEvent(server, &origin, &emitNodes[i].nodeId, &eventNodeId); #endif } @@ -55485,3296 +60666,6147 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, } cleanup: - for (size_t i=0; i<EMIT_REFS_ROOT_COUNT; i++) { - UA_Array_delete(emitRefTypes[i], emitRefTypesSize[i], &UA_TYPES[UA_TYPES_NODEID]); - } UA_Array_delete(emitNodes, emitNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); - UA_UNLOCK(server->serviceMutex); return retval; } +UA_StatusCode +UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, + const UA_NodeId origin, UA_ByteString *outEventId, + const UA_Boolean deleteEventNode) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode res = + triggerEvent(server, eventNodeId, origin, outEventId, deleteEventNode); + UA_UNLOCK(&server->serviceMutex); + return res; +} #endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_log_stdout.c" ***********************************/ +/**** amalgamated original file "/src/server/ua_subscription_events_filter.c" ****/ -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2016-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH + * Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + * Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner) */ -#include <stdio.h> - -#if UA_MULTITHREADING >= 200 -#include <pthread.h> -static pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS -/* ANSI escape sequences for color output taken from here: - * https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c*/ +typedef struct { + UA_Server *server; + UA_Session *session; + const UA_NodeId *eventNode; + const UA_ContentFilter *contentFilter; + UA_ContentFilterResult *contentFilterResult; + UA_Variant *valueResult; + UA_UInt16 index; +} UA_FilterOperatorContext; -#ifdef UA_ENABLE_LOG_COLORS -# define ANSI_COLOR_RED "\x1b[31m" -# define ANSI_COLOR_GREEN "\x1b[32m" -# define ANSI_COLOR_YELLOW "\x1b[33m" -# define ANSI_COLOR_BLUE "\x1b[34m" -# define ANSI_COLOR_MAGENTA "\x1b[35m" -# define ANSI_COLOR_CYAN "\x1b[36m" -# define ANSI_COLOR_RESET "\x1b[0m" -#else -# define ANSI_COLOR_RED "" -# define ANSI_COLOR_GREEN "" -# define ANSI_COLOR_YELLOW "" -# define ANSI_COLOR_BLUE "" -# define ANSI_COLOR_MAGENTA "" -# define ANSI_COLOR_CYAN "" -# define ANSI_COLOR_RESET "" -#endif +static UA_StatusCode +evaluateWhereClauseContentFilter(UA_FilterOperatorContext *ctx); -const char *logLevelNames[6] = {"trace", "debug", - ANSI_COLOR_GREEN "info", - ANSI_COLOR_YELLOW "warn", - ANSI_COLOR_RED "error", - ANSI_COLOR_MAGENTA "fatal"}; -const char *logCategoryNames[7] = {"network", "channel", "session", "server", - "client", "userland", "securitypolicy"}; +/* Resolves a variant of type string or boolean into a corresponding status code */ +static UA_StatusCode +resolveBoolean(UA_Variant operand) { + UA_String value; + value = UA_STRING("True"); + if(((operand.type == &UA_TYPES[UA_TYPES_STRING]) && + (UA_String_equal((UA_String *)operand.data, &value))) || + ((operand.type == &UA_TYPES[UA_TYPES_BOOLEAN]) && + (*(UA_Boolean *)operand.data == UA_TRUE))) { + return UA_STATUSCODE_GOOD; + } + value = UA_STRING("False"); + if(((operand.type == &UA_TYPES[UA_TYPES_STRING]) && + (UA_String_equal((UA_String *)operand.data, &value))) || + ((operand.type == &UA_TYPES[UA_TYPES_BOOLEAN]) && + (*(UA_Boolean *)operand.data == UA_FALSE))) { + return UA_STATUSCODE_BADNOMATCH; + } -#ifdef __clang__ -__attribute__((__format__(__printf__, 4 , 0))) -#endif -void -UA_Log_Stdout_log(void *context, UA_LogLevel level, UA_LogCategory category, - const char *msg, va_list args) { + /* If the operand can't be resolved, an error is returned */ + return UA_STATUSCODE_BADFILTEROPERANDINVALID; +} - /* Assume that context is casted to UA_LogLevel */ - /* TODO we may later change this to a struct with bitfields to filter on category */ - if ( context != NULL && (UA_LogLevel)(uintptr_t)context > level ) - return; +/* Part 4: 7.4.4.5 SimpleAttributeOperand + * The clause can point to any attribute of nodes. Either a child of the event + * node and also the event type. */ +static UA_StatusCode +resolveSimpleAttributeOperand(UA_Server *server, UA_Session *session, + const UA_NodeId *origin, + const UA_SimpleAttributeOperand *sao, + UA_Variant *value) { + /* Prepare the ReadValueId */ + UA_ReadValueId rvi; + UA_ReadValueId_init(&rvi); + rvi.indexRange = sao->indexRange; + rvi.attributeId = sao->attributeId; - UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset(); - UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset); + UA_DataValue v; -#if UA_MULTITHREADING >= 200 - pthread_mutex_lock(&printf_mutex); + if(sao->browsePathSize == 0) { + /* If this list (browsePath) is empty, the Node is the instance of the + * TypeDefinition. (Part 4, 7.4.4.5) */ + rvi.nodeId = *origin; + + /* A Condition is an indirection. Look up the target node. */ + /* TODO: check for Branches! One Condition could have multiple Branches */ + UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE); + if(UA_NodeId_equal(&sao->typeDefinitionId, &conditionTypeId)) { +#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + UA_StatusCode res = UA_getConditionId(server, origin, &rvi.nodeId); + if(res != UA_STATUSCODE_GOOD) + return res; +#else + return UA_STATUSCODE_BADNOTSUPPORTED; #endif + } - printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t", - dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec, - (int)(tOffset / UA_DATETIME_SEC / 36), logLevelNames[level], logCategoryNames[category]); - vprintf(msg, args); - printf("\n"); - fflush(stdout); + v = UA_Server_readWithSession(server, session, &rvi, + UA_TIMESTAMPSTORETURN_NEITHER); + } else { + /* Resolve the browse path, starting from the event-source (and not the + * typeDefinitionId). */ + UA_BrowsePathResult bpr = + browseSimplifiedBrowsePath(server, *origin, + sao->browsePathSize, sao->browsePath); + if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD) + bpr.statusCode = UA_STATUSCODE_BADNOTFOUND; + if(bpr.statusCode != UA_STATUSCODE_GOOD) { + UA_StatusCode res = bpr.statusCode; + UA_BrowsePathResult_clear(&bpr); + return res; + } -#if UA_MULTITHREADING >= 200 - pthread_mutex_unlock(&printf_mutex); -#endif + /* Use the first match */ + rvi.nodeId = bpr.targets[0].targetId.nodeId; + v = UA_Server_readWithSession(server, session, &rvi, + UA_TIMESTAMPSTORETURN_NEITHER); + UA_BrowsePathResult_clear(&bpr); + } + + /* Move the result to the output */ + if(v.status == UA_STATUSCODE_GOOD && v.hasValue) + *value = v.value; + else + UA_Variant_clear(&v.value); + return v.status; } -void -UA_Log_Stdout_clear(void *logContext) { +/* Resolve operands to variants according to the operand type. + * Part 4: 7.17.3 Table 142 specifies the allowed types. */ +static UA_Variant +resolveOperand(UA_FilterOperatorContext *ctx, UA_UInt16 nr) { + UA_StatusCode res; + UA_Variant variant; + UA_Variant_init(&variant); + UA_ExtensionObject *op = &ctx->contentFilter->elements[ctx->index].filterOperands[nr]; + if(op->content.decoded.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) { + /* SimpleAttributeOperand */ + res = resolveSimpleAttributeOperand(ctx->server, ctx->session, ctx->eventNode, + (UA_SimpleAttributeOperand *)op->content.decoded.data, + &variant); + } else if(op->content.decoded.type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) { + /* LiteralOperand */ + variant = ((UA_LiteralOperand *)op->content.decoded.data)->value; + res = UA_STATUSCODE_GOOD; + } else if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) { + /* ElementOperand */ + UA_UInt16 oldIndex = ctx->index; + ctx->index = (UA_UInt16)((UA_ElementOperand *)op->content.decoded.data)->index; + res = evaluateWhereClauseContentFilter(ctx); + variant = ctx->valueResult[ctx->index]; + ctx->index = oldIndex; /* restore the old index */ + } else { + res = UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + if(res != UA_STATUSCODE_GOOD && res != UA_STATUSCODE_BADNOMATCH) { + variant.type = NULL; + ctx->contentFilterResult->elementResults[ctx->index].operandStatusCodes[nr] = res; + } + + return variant; } -const UA_Logger UA_Log_Stdout_ = {UA_Log_Stdout_log, NULL, UA_Log_Stdout_clear}; -const UA_Logger *UA_Log_Stdout = &UA_Log_Stdout_; +static UA_StatusCode +ofTypeOperator(UA_FilterOperatorContext *ctx) { + UA_ContentFilterElement *pElement = &ctx->contentFilter->elements[ctx->index]; + UA_Boolean result = false; + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + if(pElement->filterOperandsSize != 1) + return UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + if(pElement->filterOperands[0].content.decoded.type != + &UA_TYPES[UA_TYPES_LITERALOPERAND]) + return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + + UA_LiteralOperand *literalOperand = + (UA_LiteralOperand *) pElement->filterOperands[0].content.decoded.data; + if(!UA_Variant_isScalar(&literalOperand->value)) + return UA_STATUSCODE_BADEVENTFILTERINVALID; -/* By default the client and server is configured with UA_Log_Stdout - This constructs a logger with a configurable max log level */ + if(literalOperand->value.type != &UA_TYPES[UA_TYPES_NODEID] || literalOperand->value.data == NULL) + return UA_STATUSCODE_BADEVENTFILTERINVALID; -UA_Logger UA_Log_Stdout_withLevel(UA_LogLevel minlevel) -{ - UA_Logger logger = {UA_Log_Stdout_log, (void*)minlevel, UA_Log_Stdout_clear}; - return logger; + UA_NodeId *literalOperandNodeId = (UA_NodeId *) literalOperand->value.data; + UA_Variant typeNodeIdVariant; + UA_Variant_init(&typeNodeIdVariant); + UA_StatusCode readStatusCode = + readObjectProperty(ctx->server, *ctx->eventNode, + UA_QUALIFIEDNAME(0, "EventType"), &typeNodeIdVariant); + if(readStatusCode != UA_STATUSCODE_GOOD) + return readStatusCode; + + if(!UA_Variant_isScalar(&typeNodeIdVariant) || + typeNodeIdVariant.type != &UA_TYPES[UA_TYPES_NODEID] || + typeNodeIdVariant.data == NULL) { + UA_LOG_ERROR(&ctx->server->config.logger, UA_LOGCATEGORY_SERVER, + "EventType has an invalid type."); + UA_Variant_clear(&typeNodeIdVariant); + return UA_STATUSCODE_BADINTERNALERROR; + } + /* check if the eventtype-nodeid is equal to the given oftype argument */ + result = UA_NodeId_equal((UA_NodeId*) typeNodeIdVariant.data, literalOperandNodeId); + /* check if the eventtype-nodeid is a subtype of the given oftype argument */ + if(!result) + result = isNodeInTree_singleRef(ctx->server, + (UA_NodeId*) typeNodeIdVariant.data, + literalOperandNodeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE); + UA_Variant_clear(&typeNodeIdVariant); + if(!result) + return UA_STATUSCODE_BADNOMATCH; + return UA_STATUSCODE_GOOD; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_accesscontrol_default.c" ***********************************/ - -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. - * - * Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH - * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) - */ +static UA_StatusCode +andOperator(UA_FilterOperatorContext *ctx) { + UA_StatusCode firstBoolean_and = resolveBoolean(resolveOperand(ctx, 0)); + if(firstBoolean_and == UA_STATUSCODE_BADNOMATCH) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + return UA_STATUSCODE_BADNOMATCH; + } + /* Evaluation of second operand */ + UA_StatusCode secondBoolean = resolveBoolean(resolveOperand(ctx, 1)); + /* Filteroperator AND */ + if(secondBoolean == UA_STATUSCODE_BADNOMATCH) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + return UA_STATUSCODE_BADNOMATCH; + } + if((firstBoolean_and == UA_STATUSCODE_GOOD) && + (secondBoolean == UA_STATUSCODE_GOOD)) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + return UA_STATUSCODE_GOOD; + } + return UA_STATUSCODE_BADFILTERELEMENTINVALID; +} +static UA_StatusCode +orOperator(UA_FilterOperatorContext *ctx) { + UA_StatusCode firstBoolean_or = resolveBoolean(resolveOperand(ctx, 0)); + if(firstBoolean_or == UA_STATUSCODE_GOOD) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + return UA_STATUSCODE_GOOD; + } + /* Evaluation of second operand */ + UA_StatusCode secondBoolean = resolveBoolean(resolveOperand(ctx, 1)); + if(secondBoolean == UA_STATUSCODE_GOOD) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + return UA_STATUSCODE_GOOD; + } + if((firstBoolean_or == UA_STATUSCODE_BADNOMATCH) && + (secondBoolean == UA_STATUSCODE_BADNOMATCH)) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + return UA_STATUSCODE_BADNOMATCH; + } + return UA_STATUSCODE_BADFILTERELEMENTINVALID; +} -/* Example access control management. Anonymous and username / password login. - * The access rights are maximally permissive. */ +static UA_Boolean +isNumericUnsigned(UA_UInt32 dataTypeKind){ + if(dataTypeKind == UA_DATATYPEKIND_UINT64 || + dataTypeKind == UA_DATATYPEKIND_UINT32 || + dataTypeKind == UA_DATATYPEKIND_UINT16 || + dataTypeKind == UA_DATATYPEKIND_BYTE) + return true; + return false; +} -typedef struct { - UA_Boolean allowAnonymous; - size_t usernamePasswordLoginSize; - UA_UsernamePasswordLogin *usernamePasswordLogin; -} AccessControlContext; +static UA_Boolean +isNumericSigned(UA_UInt32 dataTypeKind){ + if(dataTypeKind == UA_DATATYPEKIND_INT64 || + dataTypeKind == UA_DATATYPEKIND_INT32 || + dataTypeKind == UA_DATATYPEKIND_INT16 || + dataTypeKind == UA_DATATYPEKIND_SBYTE) + return true; + return false; +} -#define ANONYMOUS_POLICY "open62541-anonymous-policy" -#define USERNAME_POLICY "open62541-username-policy" -const UA_String anonymous_policy = UA_STRING_STATIC(ANONYMOUS_POLICY); -const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY); +static UA_Boolean +isFloatingPoint(UA_UInt32 dataTypeKind){ + if(dataTypeKind == UA_DATATYPEKIND_FLOAT || + dataTypeKind == UA_DATATYPEKIND_DOUBLE) + return true; + return false; +} -/************************/ -/* Access Control Logic */ -/************************/ +static UA_Boolean +isStringType(UA_UInt32 dataTypeKind){ + if(dataTypeKind == UA_DATATYPEKIND_STRING || + dataTypeKind == UA_DATATYPEKIND_BYTESTRING) + return true; + return false; +} static UA_StatusCode -activateSession_default(UA_Server *server, UA_AccessControl *ac, - const UA_EndpointDescription *endpointDescription, - const UA_ByteString *secureChannelRemoteCertificate, - const UA_NodeId *sessionId, - const UA_ExtensionObject *userIdentityToken, - void **sessionContext) { - AccessControlContext *context = (AccessControlContext*)ac->context; +implicitNumericVariantTransformation(UA_Variant *variant, void *data){ + if(variant->type == &UA_TYPES[UA_TYPES_UINT64]){ + *(UA_UInt64 *)data = *(UA_UInt64 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_UINT32]){ + *(UA_UInt64 *)data = *(UA_UInt32 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_UINT16]){ + *(UA_UInt64 *)data = *(UA_UInt16 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_BYTE]){ + *(UA_UInt64 *)data = *(UA_Byte *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_INT64]){ + *(UA_Int64 *)data = *(UA_Int64 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_INT32]){ + *(UA_Int64 *)data = *(UA_Int32 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_INT16]){ + *(UA_Int64 *)data = *(UA_Int16 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_SBYTE]){ + *(UA_Int64 *)data = *(UA_SByte *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_DOUBLE]){ + *(UA_Double *)data = *(UA_Double *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_DOUBLE]); + } else if(variant->type == &UA_TYPES[UA_TYPES_SBYTE]){ + *(UA_Double *)data = *(UA_Float *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_DOUBLE]); + } else { + return UA_STATUSCODE_BADTYPEMISMATCH; + } + return UA_STATUSCODE_GOOD; +} - /* The empty token is interpreted as anonymous */ - if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { - if(!context->allowAnonymous) - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; +static UA_StatusCode +implicitNumericVariantTransformationUnsingedToSigned(UA_Variant *variant, void *data){ + if(variant->type == &UA_TYPES[UA_TYPES_UINT64]){ + if(*(UA_UInt64 *)variant->data > UA_INT64_MAX) + return UA_STATUSCODE_BADTYPEMISMATCH; + *(UA_Int64 *)data = *(UA_Int64 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_UINT32]){ + *(UA_Int64 *)data = *(UA_Int32 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_UINT16]){ + *(UA_Int64 *)data = *(UA_Int16 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_BYTE]){ + *(UA_Int64 *)data = *(UA_Byte *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]); + } else { + return UA_STATUSCODE_BADTYPEMISMATCH; + } + return UA_STATUSCODE_GOOD; +} - /* No userdata atm */ - *sessionContext = NULL; - return UA_STATUSCODE_GOOD; +static UA_StatusCode +implicitNumericVariantTransformationSignedToUnSigned(UA_Variant *variant, void *data){ + if(*(UA_Int64 *)variant->data < 0) + return UA_STATUSCODE_BADTYPEMISMATCH; + if(variant->type == &UA_TYPES[UA_TYPES_INT64]){ + *(UA_UInt64 *)data = *(UA_UInt64 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_INT32]){ + *(UA_UInt64 *)data = *(UA_UInt32 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_INT16]){ + *(UA_UInt64 *)data = *(UA_UInt16 *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else if(variant->type == &UA_TYPES[UA_TYPES_SBYTE]){ + *(UA_UInt64 *)data = *(UA_Byte *)variant->data; + UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]); + } else { + return UA_STATUSCODE_BADTYPEMISMATCH; } + return UA_STATUSCODE_GOOD; +} - /* Could the token be decoded? */ - if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED) - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; +/* 0 -> Same Type, 1 -> Implicit Cast, 2 -> Only explicit Cast, -1 -> cast invalid */ +static UA_SByte convertLookup[21][21] = { + { 0, 1,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1}, + { 2, 0,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1}, + {-1,-1, 0,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, + {-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1}, + { 2, 2,-1,-1, 0,-1, 2,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1}, + {-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1, 2,-1,-1, 1,-1,-1,-1,-1,-1,-1}, + { 2, 2,-1,-1, 1,-1, 0,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1}, + {-1,-1, 2,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 0, 1, 1,-1, 2,-1, 2,-1,-1, 2, 1, 1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 2, 0, 1,-1, 2, 2, 2,-1,-1, 2, 2, 1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 0,-1, 2, 2, 2,-1,-1, 2, 2, 2,-1}, + {-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1, 0,-1,-1, 1,-1,-1,-1,-1,-1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 0,-1, 2,-1,-1, 1, 1, 1,-1}, + {-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1,-1, 0,-1,-1,-1, 2, 1, 1,-1}, + { 1, 1,-1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,-1, 0, 2, 2, 1, 1, 1,-1}, + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 0,-1,-1,-1,-1,-1}, + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 0,-1,-1,-1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 2, 1, 2,-1,-1, 0, 1, 1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 2, 1, 1,-1, 2, 2, 2,-1,-1, 2, 0, 1,-1}, + { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 1,-1, 2, 2, 2,-1,-1, 2, 2, 0,-1}, + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0} +}; - /* Anonymous login */ - if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) { - if(!context->allowAnonymous) - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; +/* This array maps the index of the + * standard DataType-Kind order to the + * order of the type convertion array */ +static UA_Byte dataTypeKindIndex[30] = { + 0, 12, 1, 8, 17, + 9, 18, 10, 19, 6, + 4, 14, 3, 7, 2, + 20, 11, 5, 13, 16, + 15, 255,255,255,255, + 255,255,255,255,255 +}; - const UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*) - userIdentityToken->content.decoded.data; +/* The OPC UA Standard defines in Part 4 several data type casting-rules. (see + * 1.04 part 4 Table 122) + * Return: + * 0 -> same type + * 1 -> types can be casted implicit + * 2 -> types can only be explicitly casted + * -1 -> types can't be casted */ +static UA_SByte +checkTypeCastingOption(const UA_DataType *cast_target, const UA_DataType *cast_source) { + UA_Byte firstOperatorTypeKindIndex = dataTypeKindIndex[cast_target->typeKind]; + UA_Byte secondOperatorTypeKindIndex = dataTypeKindIndex[cast_source->typeKind]; + if(firstOperatorTypeKindIndex == UA_BYTE_MAX || + secondOperatorTypeKindIndex == UA_BYTE_MAX) + return -1; - /* Compatibility notice: Siemens OPC Scout v10 provides an empty - * policyId. This is not compliant. For compatibility, assume that empty - * policyId == ANONYMOUS_POLICY */ - if(token->policyId.data && !UA_String_equal(&token->policyId, &anonymous_policy)) - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + return convertLookup[firstOperatorTypeKindIndex][secondOperatorTypeKindIndex]; +} - /* No userdata atm */ - *sessionContext = NULL; - return UA_STATUSCODE_GOOD; +/* Compare operation for equal, gt, le, gte, lee + * UA_STATUSCODE_GOOD if the comparison was true + * UA_STATUSCODE_BADNOMATCH if the comparison was false + * UA_STATUSCODE_BADFILTEROPERATORINVALID for invalid operators + * UA_STATUSCODE_BADTYPEMISMATCH if one of the operands was not numeric + * ToDo Array-Casting + */ +static UA_StatusCode +compareOperation(UA_Variant *firstOperand, UA_Variant *secondOperand, UA_FilterOperator op) { + /* get precedence of the operand types */ + UA_Int16 firstOperand_precedence = UA_DataType_getPrecedence(firstOperand->type); + UA_Int16 secondOperand_precedence = UA_DataType_getPrecedence(secondOperand->type); + /* if the types are not equal and one of the precedence-ranks is -1, then there is + no implicit conversion possible and therefore no compare */ + if(!UA_NodeId_equal(&firstOperand->type->typeId, &secondOperand->type->typeId) && + (firstOperand_precedence == -1 || secondOperand_precedence == -1)){ + return UA_STATUSCODE_BADTYPEMISMATCH; } + /* check if the precedence order of the operators is swapped */ + UA_Variant *firstCompareOperand = firstOperand; + UA_Variant *secondCompareOperand = secondOperand; + UA_Boolean swapped = false; + if (firstOperand_precedence < secondOperand_precedence){ + firstCompareOperand = secondOperand; + secondCompareOperand = firstOperand; + swapped = true; + } + UA_SByte castRule = + checkTypeCastingOption(firstCompareOperand->type, secondCompareOperand->type); - /* Username and password */ - if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) { - const UA_UserNameIdentityToken *userToken = - (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data; - - if(!UA_String_equal(&userToken->policyId, &username_policy)) - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; - - /* The userToken has been decrypted by the server before forwarding - * it to the plugin. This information can be used here. */ - /* if(userToken->encryptionAlgorithm.length > 0) {} */ - - /* Empty username and password */ - if(userToken->userName.length == 0 && userToken->password.length == 0) - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + if(!(castRule == 0 || castRule == 1)){ + return UA_STATUSCODE_BADTYPEMISMATCH; + } - /* Try to match username/pw */ - UA_Boolean match = false; - for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) { - if(UA_String_equal(&userToken->userName, &context->usernamePasswordLogin[i].username) && - UA_String_equal(&userToken->password, &context->usernamePasswordLogin[i].password)) { - match = true; - break; + /* The operand Data-Types influence the behavior and steps for the comparison. + * We need to check the operand types and store a rule which is used to select + * the right behavior afterwards. */ + enum compareHandlingRuleEnum { + UA_TYPES_EQUAL_ORDERED, + UA_TYPES_EQUAL_UNORDERED, + UA_TYPES_DIFFERENT_NUMERIC_UNSIGNED, + UA_TYPES_DIFFERENT_NUMERIC_SIGNED, + UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT, + UA_TYPES_DIFFERENT_TEXT, + UA_TYPES_DIFFERENT_COMPARE_FORBIDDEN, + UA_TYPES_DIFFERENT_COMPARE_EXPLIC, + UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED, + UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED + } compareHandlingRuleEnum; + + if(castRule == 0 && + (UA_DataType_isNumeric(firstOperand->type) || + firstCompareOperand->type->typeKind == (UA_UInt32) UA_DATATYPEKIND_DATETIME || + firstCompareOperand->type->typeKind == (UA_UInt32) UA_DATATYPEKIND_STRING || + firstCompareOperand->type->typeKind == (UA_UInt32) UA_DATATYPEKIND_BYTESTRING)){ + /* Data-Types with a natural order (allow le, gt, lee, gte) */ + compareHandlingRuleEnum = UA_TYPES_EQUAL_ORDERED; + } else if(castRule == 0){ + /* Data-Types without a natural order (le, gt, lee, gte are not allowed) */ + compareHandlingRuleEnum = UA_TYPES_EQUAL_UNORDERED; + } else if(castRule == 1 && + isNumericSigned(firstOperand->type->typeKind) && + isNumericSigned(secondOperand->type->typeKind)){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_NUMERIC_SIGNED; + } else if(castRule == 1 && + isNumericUnsigned(firstOperand->type->typeKind) && + isNumericUnsigned(secondOperand->type->typeKind)){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_NUMERIC_UNSIGNED; + } else if(castRule == 1 && + isFloatingPoint(firstOperand->type->typeKind) && + isFloatingPoint(secondOperand->type->typeKind)){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT; + } else if(castRule == 1 && + isStringType(firstOperand->type->typeKind)&& + isStringType(secondOperand->type->typeKind)){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_TEXT; + } else if(castRule == 1 && + isNumericSigned(firstOperand->type->typeKind) && + isNumericUnsigned(secondOperand->type->typeKind)){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED; + } else if(castRule == 1 && + isNumericSigned(secondOperand->type->typeKind) && + isNumericUnsigned(firstOperand->type->typeKind)){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED; + } else if(castRule == -1 || castRule == 2){ + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_COMPARE_EXPLIC; + } else { + compareHandlingRuleEnum = UA_TYPES_DIFFERENT_COMPARE_FORBIDDEN; + } + + if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_COMPARE_FORBIDDEN) + return UA_STATUSCODE_BADFILTEROPERATORINVALID; + + if(swapped){ + firstCompareOperand = secondCompareOperand; + secondCompareOperand = firstCompareOperand; + } + + if(op == UA_FILTEROPERATOR_EQUALS){ + UA_Byte variantContent[16]; + memset(&variantContent, 0, sizeof(UA_Byte) * 16); + if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_SIGNED || + compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_UNSIGNED || + compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT) { + implicitNumericVariantTransformation(firstCompareOperand, variantContent); + implicitNumericVariantTransformation(secondCompareOperand, &variantContent[8]); + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED) { + implicitNumericVariantTransformation(firstCompareOperand, variantContent); + implicitNumericVariantTransformationUnsingedToSigned(secondCompareOperand, &variantContent[8]); + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED) { + implicitNumericVariantTransformation(firstCompareOperand, variantContent); + implicitNumericVariantTransformationSignedToUnSigned(secondCompareOperand, &variantContent[8]); + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_TEXT) { + firstCompareOperand->type = &UA_TYPES[UA_TYPES_STRING]; + secondCompareOperand->type = &UA_TYPES[UA_TYPES_STRING]; + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_COMPARE_FORBIDDEN || + compareHandlingRuleEnum == UA_TYPES_DIFFERENT_COMPARE_EXPLIC ){ + return UA_STATUSCODE_BADFILTEROPERATORINVALID; + } + if(UA_order(firstCompareOperand, secondCompareOperand, &UA_TYPES[UA_TYPES_VARIANT]) == UA_ORDER_EQ) { + return UA_STATUSCODE_GOOD; + } + } else { + UA_Byte variantContent[16]; + memset(&variantContent, 0, sizeof(UA_Byte) * 16); + if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_SIGNED || + compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_UNSIGNED || + compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT) { + implicitNumericVariantTransformation(firstCompareOperand, variantContent); + implicitNumericVariantTransformation(secondCompareOperand, &variantContent[8]); + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED) { + implicitNumericVariantTransformation(firstCompareOperand, variantContent); + implicitNumericVariantTransformationUnsingedToSigned(secondCompareOperand, &variantContent[8]); + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED) { + implicitNumericVariantTransformation(firstCompareOperand, variantContent); + implicitNumericVariantTransformationSignedToUnSigned(secondCompareOperand, &variantContent[8]); + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_TEXT) { + firstCompareOperand->type = &UA_TYPES[UA_TYPES_STRING]; + secondCompareOperand->type = &UA_TYPES[UA_TYPES_STRING]; + } else if(compareHandlingRuleEnum == UA_TYPES_EQUAL_UNORDERED) { + return UA_STATUSCODE_BADFILTEROPERATORINVALID; + } else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_COMPARE_FORBIDDEN || + compareHandlingRuleEnum == UA_TYPES_DIFFERENT_COMPARE_EXPLIC) { + return UA_STATUSCODE_BADFILTEROPERATORINVALID; + } + UA_Order gte_result = UA_order(firstCompareOperand, secondCompareOperand, + &UA_TYPES[UA_TYPES_VARIANT]); + if(op == UA_FILTEROPERATOR_LESSTHAN) { + if(gte_result == UA_ORDER_LESS) { + return UA_STATUSCODE_GOOD; + } + } else if(op == UA_FILTEROPERATOR_GREATERTHAN) { + if(gte_result == UA_ORDER_MORE) { + return UA_STATUSCODE_GOOD; + } + } else if(op == UA_FILTEROPERATOR_LESSTHANOREQUAL) { + if(gte_result == UA_ORDER_LESS || gte_result == UA_ORDER_EQ) { + return UA_STATUSCODE_GOOD; + } + } else if(op == UA_FILTEROPERATOR_GREATERTHANOREQUAL) { + if(gte_result == UA_ORDER_MORE || gte_result == UA_ORDER_EQ) { + return UA_STATUSCODE_GOOD; } } - if(!match) - return UA_STATUSCODE_BADUSERACCESSDENIED; - - /* No userdata atm */ - *sessionContext = NULL; - return UA_STATUSCODE_GOOD; } - - /* Unsupported token type */ - return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + return UA_STATUSCODE_BADNOMATCH; } -static void -closeSession_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext) { - /* no context to clean up */ +static UA_StatusCode +compareOperator(UA_FilterOperatorContext *ctx) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + UA_Variant firstOperand = resolveOperand(ctx, 0); + if(UA_Variant_isEmpty(&firstOperand)) + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + UA_Variant secondOperand = resolveOperand(ctx, 1); + if(UA_Variant_isEmpty(&secondOperand)) { + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + /* ToDo remove the following restriction: Add support for arrays */ + if(!UA_Variant_isScalar(&firstOperand) || !UA_Variant_isScalar(&secondOperand)){ + return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + } + return compareOperation(&firstOperand, &secondOperand, + ctx->contentFilter->elements[ctx->index].filterOperator); } -static UA_UInt32 -getUserRightsMask_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, void *nodeContext) { - return 0xFFFFFFFF; +static UA_StatusCode +bitwiseOperator(UA_FilterOperatorContext *ctx) { + /* The bitwise operators all have 2 operands which are evaluated equally. */ + UA_Variant firstOperand = resolveOperand(ctx, 0); + if(UA_Variant_isEmpty(&firstOperand)) { + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + UA_Variant secondOperand = resolveOperand(ctx, 1); + if(UA_Variant_isEmpty(&secondOperand)) { + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + + UA_Boolean bitwiseAnd = + ctx->contentFilter->elements[ctx->index].filterOperator == UA_FILTEROPERATOR_BITWISEAND; + + /* check if the operators are integers */ + if(!UA_DataType_isNumeric(firstOperand.type) || + !UA_DataType_isNumeric(secondOperand.type) || + !UA_Variant_isScalar(&firstOperand) || + !UA_Variant_isScalar(&secondOperand) || + (firstOperand.type == &UA_TYPES[UA_TYPES_DOUBLE]) || + (secondOperand.type == &UA_TYPES[UA_TYPES_DOUBLE]) || + (secondOperand.type == &UA_TYPES[UA_TYPES_FLOAT]) || + (firstOperand.type == &UA_TYPES[UA_TYPES_FLOAT])) { + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + + /* check which is the return type (higher precedence == bigger integer)*/ + UA_Int16 precedence = UA_DataType_getPrecedence(firstOperand.type); + if(precedence > UA_DataType_getPrecedence(secondOperand.type)) { + precedence = UA_DataType_getPrecedence(secondOperand.type); + } + + switch(precedence){ + case 3: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_INT64]; + UA_Int64 result_int64; + if(bitwiseAnd) { + result_int64 = *((UA_Int64 *)firstOperand.data) & *((UA_Int64 *)secondOperand.data); + } else { + result_int64 = *((UA_Int64 *)firstOperand.data) | *((UA_Int64 *)secondOperand.data); + } + UA_Int64_copy(&result_int64, (UA_Int64 *) ctx->valueResult[ctx->index].data); + break; + case 4: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_UINT64]; + UA_UInt64 result_uint64s; + if(bitwiseAnd) { + result_uint64s = *((UA_UInt64 *)firstOperand.data) & *((UA_UInt64 *)secondOperand.data); + } else { + result_uint64s = *((UA_UInt64 *)firstOperand.data) | *((UA_UInt64 *)secondOperand.data); + } + UA_UInt64_copy(&result_uint64s, (UA_UInt64 *) ctx->valueResult[ctx->index].data); + break; + case 5: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_INT32]; + UA_Int32 result_int32; + if(bitwiseAnd) { + result_int32 = *((UA_Int32 *)firstOperand.data) & *((UA_Int32 *)secondOperand.data); + } else { + result_int32 = *((UA_Int32 *)firstOperand.data) | *((UA_Int32 *)secondOperand.data); + } + UA_Int32_copy(&result_int32, (UA_Int32 *) ctx->valueResult[ctx->index].data); + break; + case 6: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_UINT32]; + UA_UInt32 result_uint32; + if(bitwiseAnd) { + result_uint32 = *((UA_UInt32 *)firstOperand.data) & *((UA_UInt32 *)secondOperand.data); + } else { + result_uint32 = *((UA_UInt32 *)firstOperand.data) | *((UA_UInt32 *)secondOperand.data); + } + UA_UInt32_copy(&result_uint32, (UA_UInt32 *) ctx->valueResult[ctx->index].data); + break; + case 8: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_INT16]; + UA_Int16 result_int16; + if(bitwiseAnd) { + result_int16 = *((UA_Int16 *)firstOperand.data) & *((UA_Int16 *)secondOperand.data); + } else { + result_int16 = *((UA_Int16 *)firstOperand.data) | *((UA_Int16 *)secondOperand.data); + } + UA_Int16_copy(&result_int16, (UA_Int16 *) ctx->valueResult[ctx->index].data); + break; + case 9: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_UINT16]; + UA_UInt16 result_uint16; + if(bitwiseAnd) { + result_uint16 = *((UA_UInt16 *)firstOperand.data) & *((UA_UInt16 *)secondOperand.data); + } else { + result_uint16 = *((UA_UInt16 *)firstOperand.data) | *((UA_UInt16 *)secondOperand.data); + } + UA_UInt16_copy(&result_uint16, (UA_UInt16 *) ctx->valueResult[ctx->index].data); + break; + case 10: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_SBYTE]; + UA_SByte result_sbyte; + if(bitwiseAnd) { + result_sbyte = *((UA_SByte *)firstOperand.data) & *((UA_SByte *)secondOperand.data); + } else { + result_sbyte = *((UA_SByte *)firstOperand.data) | *((UA_SByte *)secondOperand.data); + } + UA_SByte_copy(&result_sbyte, (UA_SByte *) ctx->valueResult[ctx->index].data); + break; + case 11: + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BYTE]; + UA_Byte result_byte; + if(bitwiseAnd) { + result_byte = *((UA_Byte *)firstOperand.data) & *((UA_Byte *)secondOperand.data); + } else { + result_byte = *((UA_Byte *)firstOperand.data) | *((UA_Byte *)secondOperand.data); + } + UA_Byte_copy(&result_byte, (UA_Byte *) ctx->valueResult[ctx->index].data); + break; + default: + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + return UA_STATUSCODE_GOOD; } -static UA_Byte -getUserAccessLevel_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, void *nodeContext) { - return 0xFF; +static UA_StatusCode +betweenOperator(UA_FilterOperatorContext *ctx) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + + UA_Variant firstOperand = resolveOperand(ctx, 0); + UA_Variant secondOperand = resolveOperand(ctx, 1); + UA_Variant thirdOperand = resolveOperand(ctx, 2); + + if((UA_Variant_isEmpty(&firstOperand) || + UA_Variant_isEmpty(&secondOperand) || + UA_Variant_isEmpty(&thirdOperand)) || + (!UA_DataType_isNumeric(firstOperand.type) || + !UA_DataType_isNumeric(secondOperand.type) || + !UA_DataType_isNumeric(thirdOperand.type)) || + (!UA_Variant_isScalar(&firstOperand) || + !UA_Variant_isScalar(&secondOperand) || + !UA_Variant_isScalar(&thirdOperand))) { + return UA_STATUSCODE_BADFILTEROPERANDINVALID; + } + + /* Between can be evaluated through greaterThanOrEqual and lessThanOrEqual */ + if(compareOperation(&firstOperand, &secondOperand, UA_FILTEROPERATOR_GREATERTHANOREQUAL) == UA_STATUSCODE_GOOD && + compareOperation(&firstOperand, &thirdOperand, UA_FILTEROPERATOR_LESSTHANOREQUAL) == UA_STATUSCODE_GOOD){ + return UA_STATUSCODE_GOOD; + } + return UA_STATUSCODE_BADNOMATCH; } -static UA_Boolean -getUserExecutable_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *methodId, void *methodContext) { - return true; -} +static UA_StatusCode +inListOperator(UA_FilterOperatorContext *ctx) { + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + UA_Variant firstOperand = resolveOperand(ctx, 0); -static UA_Boolean -getUserExecutableOnObject_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *methodId, void *methodContext, - const UA_NodeId *objectId, void *objectContext) { - return true; -} + if(UA_Variant_isEmpty(&firstOperand) || + !UA_Variant_isScalar(&firstOperand)) { + return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + } -static UA_Boolean -allowAddNode_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_AddNodesItem *item) { - return true; -} + /* Evaluating the list of operands */ + for(size_t i = 1; i < ctx->contentFilter->elements[ctx->index].filterOperandsSize; i++) { + /* Resolving the current operand */ + UA_Variant currentOperator = resolveOperand(ctx, (UA_UInt16)i); -static UA_Boolean -allowAddReference_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_AddReferencesItem *item) { - return true; + /* Check if the operand conforms to the operator*/ + if(UA_Variant_isEmpty(¤tOperator) || + !UA_Variant_isScalar(¤tOperator)) { + return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + } + if(compareOperation(&firstOperand, ¤tOperator, UA_FILTEROPERATOR_EQUALS)) { + return UA_STATUSCODE_GOOD; + } + } + return UA_STATUSCODE_BADNOMATCH; } -static UA_Boolean -allowDeleteNode_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_DeleteNodesItem *item) { - return true; +static UA_StatusCode +isNullOperator(UA_FilterOperatorContext *ctx) { + /* Checking if operand is NULL. This is done by reducing the operand to a + * variant and then checking if it is empty. */ + UA_Variant operand = resolveOperand(ctx, 0); + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + if(!UA_Variant_isEmpty(&operand)) + return UA_STATUSCODE_BADNOMATCH; + return UA_STATUSCODE_GOOD; } -static UA_Boolean -allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_DeleteReferencesItem *item) { - return true; +static UA_StatusCode +notOperator(UA_FilterOperatorContext *ctx) { + /* Inverting the boolean value of the operand. */ + UA_StatusCode res = resolveBoolean(resolveOperand(ctx, 0)); + ctx->valueResult[ctx->index].type = &UA_TYPES[UA_TYPES_BOOLEAN]; + /* invert result */ + if(res == UA_STATUSCODE_GOOD) + return UA_STATUSCODE_BADNOMATCH; + return UA_STATUSCODE_GOOD; } -static UA_Boolean -allowBrowseNode_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, void *nodeContext) { - return true; +static UA_StatusCode +evaluateWhereClauseContentFilter(UA_FilterOperatorContext *ctx) { + UA_LOCK_ASSERT(&ctx->server->serviceMutex, 1); + + if(ctx->contentFilter->elements == NULL || ctx->contentFilter->elementsSize == 0) { + /* Nothing to do.*/ + return UA_STATUSCODE_GOOD; + } + + /* The first element needs to be evaluated, this might be linked to other + * elements, which are evaluated in these cases. See 7.4.1 in Part 4. */ + UA_ContentFilterElement *pElement = &ctx->contentFilter->elements[ctx->index]; + UA_StatusCode *result = &ctx->contentFilterResult->elementResults[ctx->index].statusCode; + switch(pElement->filterOperator) { + case UA_FILTEROPERATOR_INVIEW: + /* Fallthrough */ + case UA_FILTEROPERATOR_RELATEDTO: + /* Not allowed for event WhereClause according to 7.17.3 in Part 4 */ + return UA_STATUSCODE_BADEVENTFILTERINVALID; + case UA_FILTEROPERATOR_EQUALS: + /* Fallthrough */ + case UA_FILTEROPERATOR_GREATERTHAN: + /* Fallthrough */ + case UA_FILTEROPERATOR_LESSTHAN: + /* Fallthrough */ + case UA_FILTEROPERATOR_GREATERTHANOREQUAL: + /* Fallthrough */ + case UA_FILTEROPERATOR_LESSTHANOREQUAL: + *result = compareOperator(ctx); + break; + case UA_FILTEROPERATOR_LIKE: + return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + case UA_FILTEROPERATOR_NOT: + *result = notOperator(ctx); + break; + case UA_FILTEROPERATOR_BETWEEN: + *result = betweenOperator(ctx); + break; + case UA_FILTEROPERATOR_INLIST: + /* ToDo currently only numeric types are allowed */ + *result = inListOperator(ctx); + break; + case UA_FILTEROPERATOR_ISNULL: + *result = isNullOperator(ctx); + break; + case UA_FILTEROPERATOR_AND: + *result = andOperator(ctx); + break; + case UA_FILTEROPERATOR_OR: + *result = orOperator(ctx); + break; + case UA_FILTEROPERATOR_CAST: + return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + case UA_FILTEROPERATOR_BITWISEAND: + *result = bitwiseOperator(ctx); + break; + case UA_FILTEROPERATOR_BITWISEOR: + *result = bitwiseOperator(ctx); + break; + case UA_FILTEROPERATOR_OFTYPE: + *result = ofTypeOperator(ctx); + break; + default: + return UA_STATUSCODE_BADFILTEROPERATORINVALID; + } + + if(ctx->valueResult[ctx->index].type == &UA_TYPES[UA_TYPES_BOOLEAN]) { + UA_Boolean *res = UA_Boolean_new(); + if(ctx->contentFilterResult->elementResults[ctx->index].statusCode == UA_STATUSCODE_GOOD) + *res = true; + else + *res = false; + ctx->valueResult[ctx->index].data = res; + } + return ctx->contentFilterResult->elementResults[ctx->index].statusCode; } -#ifdef UA_ENABLE_HISTORIZING -static UA_Boolean -allowHistoryUpdateUpdateData_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, - UA_PerformUpdateType performInsertReplace, - const UA_DataValue *value) { - return true; +/* Exposes the filters For unit tests */ +UA_StatusCode +UA_Server_evaluateWhereClauseContentFilter(UA_Server *server, UA_Session *session, + const UA_NodeId *eventNode, + const UA_ContentFilter *contentFilter, + UA_ContentFilterResult *contentFilterResult) { + if(contentFilter->elementsSize == 0) + return UA_STATUSCODE_GOOD; + /* TODO add maximum lenth size to the server config */ + if(contentFilter->elementsSize > 256) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_Variant valueResult[256]; + for(size_t i = 0; i < contentFilter->elementsSize; ++i) { + UA_Variant_init(&valueResult[i]); + } + + UA_FilterOperatorContext ctx; + ctx.server = server; + ctx.session = session; + ctx.eventNode = eventNode; + ctx.contentFilter = contentFilter; + ctx.contentFilterResult = contentFilterResult; + ctx.valueResult = valueResult; + ctx.index = 0; + + UA_StatusCode res = evaluateWhereClauseContentFilter(&ctx); + for(size_t i = 0; i < ctx.contentFilter->elementsSize; i++) { + if(!UA_Variant_isEmpty(&ctx.valueResult[i])) + UA_Variant_clear(&ctx.valueResult[i]); + } + return res; } static UA_Boolean -allowHistoryUpdateDeleteRawModified_default(UA_Server *server, UA_AccessControl *ac, - const UA_NodeId *sessionId, void *sessionContext, - const UA_NodeId *nodeId, - UA_DateTime startTimestamp, - UA_DateTime endTimestamp, - bool isDeleteModified) { - return true; -} -#endif +isValidEvent(UA_Server *server, const UA_NodeId *validEventParent, + const UA_NodeId *eventId) { + /* find the eventType variableNode */ + UA_QualifiedName findName = UA_QUALIFIEDNAME(0, "EventType"); + UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, *eventId, 1, &findName); + if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) { + UA_BrowsePathResult_clear(&bpr); + return false; + } -/***************************************/ -/* Create Delete Access Control Plugin */ -/***************************************/ + /* Get the EventType Property Node */ + UA_Variant tOutVariant; + UA_Variant_init(&tOutVariant); -static void clear_default(UA_AccessControl *ac) { - UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies, - ac->userTokenPoliciesSize, - &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); - ac->userTokenPolicies = NULL; - ac->userTokenPoliciesSize = 0; + /* Read the Value of EventType Property Node (the Value should be a NodeId) */ + UA_StatusCode retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId, + UA_ATTRIBUTEID_VALUE, &tOutVariant); + if(retval != UA_STATUSCODE_GOOD || + !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_NODEID])) { + UA_BrowsePathResult_clear(&bpr); + return false; + } - AccessControlContext *context = (AccessControlContext*)ac->context; + const UA_NodeId *tEventType = (UA_NodeId*)tOutVariant.data; - if (context) { - for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) { - UA_String_deleteMembers(&context->usernamePasswordLogin[i].username); - UA_String_deleteMembers(&context->usernamePasswordLogin[i].password); - } - if(context->usernamePasswordLoginSize > 0) - UA_free(context->usernamePasswordLogin); - UA_free(ac->context); - ac->context = NULL; + /* check whether the EventType is a Subtype of CondtionType + * (Part 9 first implementation) */ + UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE); + if(UA_NodeId_equal(validEventParent, &conditionTypeId) && + isNodeInTree_singleRef(server, tEventType, &conditionTypeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) { + UA_BrowsePathResult_clear(&bpr); + UA_Variant_clear(&tOutVariant); + return true; } -} -UA_StatusCode -UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous, - const UA_ByteString *userTokenPolicyUri, - size_t usernamePasswordLoginSize, - const UA_UsernamePasswordLogin *usernamePasswordLogin) { - UA_AccessControl *ac = &config->accessControl; - ac->clear = clear_default; - ac->activateSession = activateSession_default; - ac->closeSession = closeSession_default; - ac->getUserRightsMask = getUserRightsMask_default; - ac->getUserAccessLevel = getUserAccessLevel_default; - ac->getUserExecutable = getUserExecutable_default; - ac->getUserExecutableOnObject = getUserExecutableOnObject_default; - ac->allowAddNode = allowAddNode_default; - ac->allowAddReference = allowAddReference_default; - ac->allowBrowseNode = allowBrowseNode_default; + /*EventType is not a Subtype of CondtionType + *(ConditionId Clause won't be present in Events, which are not Conditions)*/ + /* check whether Valid Event other than Conditions */ + UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); + UA_Boolean isSubtypeOfBaseEvent = + isNodeInTree_singleRef(server, tEventType, &baseEventTypeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE); -#ifdef UA_ENABLE_HISTORIZING - ac->allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData_default; - ac->allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified_default; -#endif + UA_BrowsePathResult_clear(&bpr); + UA_Variant_clear(&tOutVariant); + return isSubtypeOfBaseEvent; +} - ac->allowDeleteNode = allowDeleteNode_default; - ac->allowDeleteReference = allowDeleteReference_default; +UA_StatusCode +filterEvent(UA_Server *server, UA_Session *session, + const UA_NodeId *eventNode, UA_EventFilter *filter, + UA_EventFieldList *efl, UA_EventFilterResult *result) { + if(filter->selectClausesSize == 0) + return UA_STATUSCODE_BADEVENTFILTERINVALID; - AccessControlContext *context = (AccessControlContext*) - UA_malloc(sizeof(AccessControlContext)); - if (!context) + UA_EventFieldList_init(efl); + efl->eventFields = (UA_Variant *) + UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_VARIANT]); + if(!efl->eventFields) return UA_STATUSCODE_BADOUTOFMEMORY; - memset(context, 0, sizeof(AccessControlContext)); - ac->context = context; + efl->eventFieldsSize = filter->selectClausesSize; - /* Allow anonymous? */ - context->allowAnonymous = allowAnonymous; - - /* Copy username/password to the access control plugin */ - if(usernamePasswordLoginSize > 0) { - context->usernamePasswordLogin = (UA_UsernamePasswordLogin*) - UA_malloc(usernamePasswordLoginSize * sizeof(UA_UsernamePasswordLogin)); - if(!context->usernamePasswordLogin) + /* empty event filter result */ + UA_EventFilterResult_init(result); + result->selectClauseResultsSize = filter->selectClausesSize; + result->selectClauseResults = (UA_StatusCode *) + UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_STATUSCODE]); + if(!result->selectClauseResults) { + UA_EventFieldList_clear(efl); + UA_EventFilterResult_clear(result); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + /* prepare content filter result structure */ + if(filter->whereClause.elementsSize != 0) { + result->whereClauseResult.elementResultsSize = filter->whereClause.elementsSize; + result->whereClauseResult.elementResults = (UA_ContentFilterElementResult *) + UA_Array_new(filter->whereClause.elementsSize, + &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT]); + if(!result->whereClauseResult.elementResults) { + UA_EventFieldList_clear(efl); + UA_EventFilterResult_clear(result); return UA_STATUSCODE_BADOUTOFMEMORY; - context->usernamePasswordLoginSize = usernamePasswordLoginSize; - for(size_t i = 0; i < usernamePasswordLoginSize; i++) { - UA_String_copy(&usernamePasswordLogin[i].username, &context->usernamePasswordLogin[i].username); - UA_String_copy(&usernamePasswordLogin[i].password, &context->usernamePasswordLogin[i].password); + } + for(size_t i = 0; i < result->whereClauseResult.elementResultsSize; ++i) { + result->whereClauseResult.elementResults[i].operandStatusCodesSize = + filter->whereClause.elements->filterOperandsSize; + result->whereClauseResult.elementResults[i].operandStatusCodes = + (UA_StatusCode *)UA_Array_new( + filter->whereClause.elements->filterOperandsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); + if(!result->whereClauseResult.elementResults[i].operandStatusCodes) { + UA_EventFieldList_clear(efl); + UA_EventFilterResult_clear(result); + return UA_STATUSCODE_BADOUTOFMEMORY; + } } } - /* Set the allowed policies */ - size_t policies = 0; - if(allowAnonymous) - policies++; - if(usernamePasswordLoginSize > 0) - policies++; - ac->userTokenPoliciesSize = 0; - ac->userTokenPolicies = (UA_UserTokenPolicy *) - UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); - if(!ac->userTokenPolicies) - return UA_STATUSCODE_BADOUTOFMEMORY; - ac->userTokenPoliciesSize = policies; + /* Apply the content (where) filter */ + UA_StatusCode res = + UA_Server_evaluateWhereClauseContentFilter(server, session, eventNode, + &filter->whereClause, &result->whereClauseResult); + if(res != UA_STATUSCODE_GOOD){ + UA_EventFieldList_clear(efl); + UA_EventFilterResult_clear(result); + return res; + } - policies = 0; - if(allowAnonymous) { - ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS; - ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY); - if (!ac->userTokenPolicies[policies].policyId.data) - return UA_STATUSCODE_BADOUTOFMEMORY; - policies++; + /* Apply the select filter */ + /* Check if the browsePath is BaseEventType, in which case nothing more + * needs to be checked */ + UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); + for(size_t i = 0; i < filter->selectClausesSize; i++) { + if(!UA_NodeId_equal(&filter->selectClauses[i].typeDefinitionId, &baseEventTypeId) && + !isValidEvent(server, &filter->selectClauses[i].typeDefinitionId, eventNode)) { + UA_Variant_init(&efl->eventFields[i]); + /* EventFilterResult currently isn't being used + notification->result.selectClauseResults[i] = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; */ + continue; + } + + /* TODO: Put the result into the selectClausResults */ + resolveSimpleAttributeOperand(server, session, eventNode, + &filter->selectClauses[i], &efl->eventFields[i]); } - if(usernamePasswordLoginSize > 0) { - ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME; - ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY); - if(!ac->userTokenPolicies[policies].policyId.data) - return UA_STATUSCODE_BADOUTOFMEMORY; + return UA_STATUSCODE_GOOD; +} -#if UA_LOGLEVEL <= 400 - const UA_String noneUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); - if(UA_ByteString_equal(userTokenPolicyUri, &noneUri)) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_SERVER, - "Username/Password configured, but no encrypting SecurityPolicy. " - "This can leak credentials on the network."); +/*****************************************/ +/* Validation of Filters during Creation */ +/*****************************************/ + +/* Initial select clause validation. The following checks are currently performed: + * - Check if typedefenitionid or browsepath of any clause is NULL + * - Check if the eventType is a subtype of BaseEventType + * - Check if attributeId is valid + * - Check if browsePath contains null + * - Check if indexRange is defined and if it is parsable + * - Check if attributeId is value */ +void +UA_Event_staticSelectClauseValidation(UA_Server *server, + const UA_EventFilter *eventFilter, + UA_StatusCode *result) { + /* The selectClause only has to be checked, if the size is not zero */ + if(eventFilter->selectClausesSize == 0) + return; + for(size_t i = 0; i < eventFilter->selectClausesSize; ++i) { + result[i] = UA_STATUSCODE_GOOD; + /* /typedefenitionid or browsepath of any clause is not NULL ? */ + if(UA_NodeId_isNull(&eventFilter->selectClauses[i].typeDefinitionId)) { + result[i] = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + continue; + } + /*ToDo: Check the following workaround. In UaExpert Event View the selection + * of the Server Object set up 7 select filter entries by default. The last + * element ist from node 2782 (A&C ConditionType). Since the reduced + * information model dos not contain this type, the result has a brows path of + * "null" which results in an error. */ + UA_NodeId ac_conditionType = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE); + if(UA_NodeId_equal(&eventFilter->selectClauses[i].typeDefinitionId, &ac_conditionType)) { + continue; + } + if(&eventFilter->selectClauses[i].browsePath[0] == NULL) { + result[i] = UA_STATUSCODE_BADBROWSENAMEINVALID; + continue; + } + /* eventType is a subtype of BaseEventType ? */ + UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); + if(!isNodeInTree_singleRef( + server, &eventFilter->selectClauses[i].typeDefinitionId, + &baseEventTypeId, UA_REFERENCETYPEINDEX_HASSUBTYPE)) { + result[i] = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + continue; + } + /* attributeId is valid ? */ + if(!((0 < eventFilter->selectClauses[i].attributeId) && + (eventFilter->selectClauses[i].attributeId < 28))) { + result[i] = UA_STATUSCODE_BADATTRIBUTEIDINVALID; + continue; + } + /* browsePath contains null ? */ + for(size_t j = 0; j < eventFilter->selectClauses[i].browsePathSize; ++j) { + if(UA_QualifiedName_isNull( + &eventFilter->selectClauses[i].browsePath[j])) { + result[i] = UA_STATUSCODE_BADBROWSENAMEINVALID; + break; + } + } + + /* Get the list of Subtypes from current node */ + UA_ReferenceTypeSet reftypes_interface = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); + UA_ExpandedNodeId *chilTypeNodes = NULL; + size_t chilTypeNodesSize = 0; + UA_StatusCode res; + res = browseRecursive(server, 1, &eventFilter->selectClauses[i].typeDefinitionId, + UA_BROWSEDIRECTION_FORWARD, &reftypes_interface, UA_NODECLASS_OBJECTTYPE, + true, &chilTypeNodesSize, &chilTypeNodes); + if(res!=UA_STATUSCODE_GOOD){ + result[i] = UA_STATUSCODE_BADATTRIBUTEIDINVALID; + continue; + } + + UA_Boolean subTypeContainField = false; + for (size_t j = 0; j < chilTypeNodesSize; ++j) { + /* browsPath element is defined in path */ + UA_BrowsePathResult bpr = + browseSimplifiedBrowsePath(server, chilTypeNodes[j].nodeId, + eventFilter->selectClauses[i].browsePathSize, + eventFilter->selectClauses[i].browsePath); + + if(bpr.statusCode != UA_STATUSCODE_GOOD){ + UA_BrowsePathResult_clear(&bpr); + continue; + } + subTypeContainField = true; + UA_BrowsePathResult_clear(&bpr); + } + if(!subTypeContainField) + result[i] = UA_STATUSCODE_BADNODEIDUNKNOWN; + + UA_Array_delete(chilTypeNodes, chilTypeNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + + if(result[i] != UA_STATUSCODE_GOOD) + continue; + /*indexRange is defined ? */ + if(!UA_String_equal(&eventFilter->selectClauses[i].indexRange, + &UA_STRING_NULL)) { + /* indexRange is parsable ? */ + UA_NumericRange numericRange = UA_NUMERICRANGE(""); + if(UA_NumericRange_parse(&numericRange, + eventFilter->selectClauses[i].indexRange) != + UA_STATUSCODE_GOOD) { + result[i] = UA_STATUSCODE_BADINDEXRANGEINVALID; + continue; + } + UA_free(numericRange.dimensions); + /* attributeId is value ? */ + if(eventFilter->selectClauses[i].attributeId != UA_ATTRIBUTEID_VALUE) { + result[i] = UA_STATUSCODE_BADTYPEMISMATCH; + continue; + } + } + } +} + +/* Initial content filter (where clause) check. Current checks: + * - Number of operands for each (supported) operator */ +UA_StatusCode +UA_Event_staticWhereClauseValidation(UA_Server *server, + const UA_ContentFilter *filter, + UA_ContentFilterResult *result) { + UA_ContentFilterResult_init(result); + result->elementResultsSize = filter->elementsSize; + if(result->elementResultsSize == 0) + return UA_STATUSCODE_GOOD; + result->elementResults = + (UA_ContentFilterElementResult *)UA_Array_new( + result->elementResultsSize, + &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT]); + if(!result->elementResults) + return UA_STATUSCODE_BADOUTOFMEMORY; + for(size_t i = 0; i < result->elementResultsSize; ++i) { + UA_ContentFilterElementResult *er = &result->elementResults[i]; + UA_ContentFilterElement ef = filter->elements[i]; + UA_ContentFilterElementResult_init(er); + er->operandStatusCodes = + (UA_StatusCode *)UA_Array_new( + ef.filterOperandsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); + er->operandStatusCodesSize = ef.filterOperandsSize; + + switch(ef.filterOperator) { + case UA_FILTEROPERATOR_INVIEW: + case UA_FILTEROPERATOR_RELATEDTO: { + /* Not allowed for event WhereClause according to 7.17.3 in Part 4 */ + er->statusCode = + UA_STATUSCODE_BADEVENTFILTERINVALID; + break; + } + case UA_FILTEROPERATOR_EQUALS: + case UA_FILTEROPERATOR_GREATERTHAN: + case UA_FILTEROPERATOR_LESSTHAN: + case UA_FILTEROPERATOR_GREATERTHANOREQUAL: + case UA_FILTEROPERATOR_LESSTHANOREQUAL: + case UA_FILTEROPERATOR_LIKE: + case UA_FILTEROPERATOR_CAST: + case UA_FILTEROPERATOR_BITWISEAND: + case UA_FILTEROPERATOR_BITWISEOR: { + if(ef.filterOperandsSize != 2) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + break; + } + er->statusCode = UA_STATUSCODE_GOOD; + break; + } + case UA_FILTEROPERATOR_AND: + case UA_FILTEROPERATOR_OR: { + if(ef.filterOperandsSize != 2) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + break; + } + for(size_t j = 0; j < 2; ++j) { + if(ef.filterOperands[j].content.decoded.type != + &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) { + er->operandStatusCodes[j] = + UA_STATUSCODE_BADFILTEROPERANDINVALID; + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDINVALID; + break; + } + if(((UA_ElementOperand *)ef.filterOperands[j] + .content.decoded.data)->index > filter->elementsSize - 1) { + er->operandStatusCodes[j] = + UA_STATUSCODE_BADINDEXRANGEINVALID; + er->statusCode = + UA_STATUSCODE_BADINDEXRANGEINVALID; + break; + } + } + er->statusCode = UA_STATUSCODE_GOOD; + break; + } + case UA_FILTEROPERATOR_ISNULL: + case UA_FILTEROPERATOR_NOT: { + if(ef.filterOperandsSize != 1) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + break; + } + er->statusCode = UA_STATUSCODE_GOOD; + break; + } + case UA_FILTEROPERATOR_INLIST: { + if(ef.filterOperandsSize <= 2) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + break; + } + er->statusCode = UA_STATUSCODE_GOOD; + break; + } + case UA_FILTEROPERATOR_BETWEEN: { + if(ef.filterOperandsSize != 3) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + break; + } + er->statusCode = UA_STATUSCODE_GOOD; + break; + } + case UA_FILTEROPERATOR_OFTYPE: { + if(ef.filterOperandsSize != 1) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH; + break; + } + er->operandStatusCodesSize = ef.filterOperandsSize; + if(ef.filterOperands[0].content.decoded.type != + &UA_TYPES[UA_TYPES_LITERALOPERAND]) { + er->statusCode = + UA_STATUSCODE_BADFILTEROPERANDINVALID; + break; + } + UA_LiteralOperand *literalOperand = + (UA_LiteralOperand *)ef.filterOperands[0] + .content.decoded.data; + + /* Make sure the &pOperand->nodeId is a subtype of BaseEventType */ + UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); + if(!isNodeInTree_singleRef( + server, (UA_NodeId *)literalOperand->value.data, &baseEventTypeId, + UA_REFERENCETYPEINDEX_HASSUBTYPE)) { + er->statusCode = + UA_STATUSCODE_BADNODEIDINVALID; + break; + } + er->statusCode = UA_STATUSCODE_GOOD; + break; + } + default: + er->statusCode = + UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED; + break; } -#endif - return UA_ByteString_copy(userTokenPolicyUri, - &ac->userTokenPolicies[policies].securityPolicyUri); } return UA_STATUSCODE_GOOD; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_pki_default.c" ***********************************/ +#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */ -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_openssl_common.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Wind River Systems, Inc. + * Copyright 2020 (c) basysKom GmbH * - * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB - * Copyright 2019 (c) Kalycito Infotech Private Limited - * Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB */ -#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS -#include <mbedtls/x509.h> -#include <mbedtls/x509_crt.h> -#include <mbedtls/error.h> + +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) + +#include <openssl/x509.h> +#include <openssl/evp.h> + +_UA_BEGIN_DECLS + +void saveDataToFile(const char *fileName, const UA_ByteString *str); +void UA_Openssl_Init(void); + +UA_StatusCode +UA_copyCertificate(UA_ByteString *dst, const UA_ByteString *src); + +UA_StatusCode +UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(const UA_ByteString *msg, + X509 *publicKeyX509, + const UA_ByteString *signature); +UA_StatusCode +UA_Openssl_X509_GetCertificateThumbprint(const UA_ByteString *certficate, + UA_ByteString *pThumbprint, + bool bThumbPrint); +UA_StatusCode +UA_Openssl_RSA_Oaep_Decrypt(UA_ByteString *data, + EVP_PKEY *privateKey); +UA_StatusCode +UA_Openssl_RSA_OAEP_Encrypt(UA_ByteString *data, /* The data that is encrypted. + The encrypted data will overwrite + the data that was supplied. */ + size_t paddingSize, X509 *publicX509); + +UA_StatusCode +UA_Openssl_Random_Key_PSHA256_Derive(const UA_ByteString *secret, + const UA_ByteString *seed, + UA_ByteString *out); + +UA_StatusCode +UA_Openssl_RSA_Public_GetKeyLength(X509 *publicKeyX509, UA_Int32 *keyLen); + +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(const UA_ByteString *data, + EVP_PKEY *privateKey, + UA_ByteString *outSignature); + +UA_StatusCode +UA_OpenSSL_HMAC_SHA256_Verify(const UA_ByteString *message, + const UA_ByteString *key, + const UA_ByteString *signature); + +UA_StatusCode +UA_OpenSSL_HMAC_SHA256_Sign(const UA_ByteString *message, + const UA_ByteString *key, + UA_ByteString *signature); + +UA_StatusCode +UA_OpenSSL_AES_256_CBC_Decrypt(const UA_ByteString *iv, + const UA_ByteString *key, + UA_ByteString *data /* [in/out]*/); + +UA_StatusCode +UA_OpenSSL_AES_256_CBC_Encrypt(const UA_ByteString *iv, + const UA_ByteString *key, + UA_ByteString *data /* [in/out]*/); + +UA_StatusCode +UA_OpenSSL_X509_compare(const UA_ByteString *cert, const X509 *b); + +UA_StatusCode +UA_Openssl_RSA_Private_GetKeyLength(EVP_PKEY *privateKey, + UA_Int32 *keyLen) ; + +UA_StatusCode +UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(const UA_ByteString *msg, + X509 *publicKeyX509, + const UA_ByteString *signature); + +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(const UA_ByteString *message, + EVP_PKEY *privateKey, + UA_ByteString *outSignature); +UA_StatusCode +UA_Openssl_Random_Key_PSHA1_Derive(const UA_ByteString *secret, + const UA_ByteString *seed, + UA_ByteString *out); +UA_StatusCode +UA_OpenSSL_HMAC_SHA1_Verify(const UA_ByteString *message, + const UA_ByteString *key, + const UA_ByteString *signature); + +UA_StatusCode +UA_OpenSSL_HMAC_SHA1_Sign(const UA_ByteString *message, + const UA_ByteString *key, + UA_ByteString *signature); + +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_Decrypt(UA_ByteString *data, + EVP_PKEY *privateKey); + +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_Encrypt(UA_ByteString *data, + size_t paddingSize, + X509 *publicX509); + +UA_StatusCode +UA_OpenSSL_AES_128_CBC_Decrypt(const UA_ByteString *iv, + const UA_ByteString *key, + UA_ByteString *data /* [in/out]*/); + +UA_StatusCode +UA_OpenSSL_AES_128_CBC_Encrypt(const UA_ByteString *iv, + const UA_ByteString *key, + UA_ByteString *data /* [in/out]*/); + +EVP_PKEY * +UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey); + +X509 * +UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate); + +X509 * +UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate); + +X509 * +UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate); + +UA_StatusCode +UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString *target); + +_UA_END_DECLS + +#endif /* defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */ + + +/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_version_abstraction.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + * + */ + + +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) + +#include <openssl/x509.h> + +#if !defined(OPENSSL_VERSION_NUMBER) +#error "OPENSSL_VERSION_NUMBER is not defined." #endif -#define REMOTECERTIFICATETRUSTED 1 -#define ISSUERKNOWN 2 -#define DUALPARENT 3 -#define PARENTFOUND 4 +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#define X509_STORE_CTX_set0_trusted_stack(STORE_CTX, CTX_SKTRUSTED) X509_STORE_CTX_trusted_stack(STORE_CTX, CTX_SKTRUSTED) +#endif -/************/ -/* AllowAll */ -/************/ +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER) +#define X509_STORE_CTX_get_check_issued(STORE_CTX) STORE_CTX->check_issued +#endif -static UA_StatusCode -verifyCertificateAllowAll(void *verificationContext, - const UA_ByteString *certificate) { - return UA_STATUSCODE_GOOD; +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER) +#define get_pkey_rsa(evp) ((evp)->pkey.rsa) +#else +#define get_pkey_rsa(evp) EVP_PKEY_get0_RSA(evp) +#endif + +#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER) +#define X509_get0_subject_key_id(PX509_CERT) (const ASN1_OCTET_STRING *)X509_get_ext_d2i(PX509_CERT, NID_subject_key_identifier, NULL, NULL); +#endif + +#endif /* defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */ + +/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_openssl_common.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Wind River Systems, Inc. + * Copyright 2020 (c) basysKom GmbH + * Copyright 2022 (c) Wind River Systems, Inc. + */ + +/* +modification history +-------------------- +01feb20,lan written +*/ + + +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) + +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/sha.h> +#include <openssl/x509.h> +#include <openssl/hmac.h> +#include <openssl/aes.h> +#include <openssl/pem.h> + + +#define SHA1_DIGEST_LENGTH 20 /* 160 bits */ +#define RSA_DECRYPT_BUFFER_LENGTH 2048 /* bytes */ + + +/** P_SHA256 Context */ +typedef struct UA_Openssl_P_SHA256_Ctx_ { + size_t seedLen; + size_t secretLen; + UA_Byte A[32]; /* 32 bytes of SHA256 output */ + /* + char seed[seedLen]; + char secret[secretLen]; */ +} UA_Openssl_P_SHA256_Ctx; + +#define UA_Openssl_P_SHA256_SEED(ctx) ((ctx)->A+32) +#define UA_Openssl_P_SHA256_SECRET(ctx) ((ctx)->A+32+(ctx)->seedLen) + +/** P_SHA1 Context */ +typedef struct UA_Openssl_P_SHA1_Ctx_ { + size_t seedLen; + size_t secretLen; + UA_Byte A[SHA1_DIGEST_LENGTH]; /* 20 bytes of SHA1 output */ + /* + char seed[seedLen]; + char secret[secretLen]; */ +} UA_Openssl_P_SHA1_Ctx; + +#define UA_Openssl_P_SHA1_SEED(ctx) ((ctx)->A + SHA1_DIGEST_LENGTH) +#define UA_Openssl_P_SHA1_SECRET(ctx) ((ctx)->A + SHA1_DIGEST_LENGTH +(ctx)->seedLen) + +void +UA_Openssl_Init (void) { + /* VxWorks7 has initialized the openssl. */ +#ifndef __VXWORKS__ + static UA_Int16 bInit = 0; + if (bInit == 1) + return; +#if defined(OPENSSL_API_COMPAT) && (OPENSSL_API_COMPAT < 0x10100000L) + /* only needed, if OpenSSL < V1.1 */ + OpenSSL_add_all_algorithms (); + ERR_load_crypto_strings (); +#endif + bInit = 1; +#endif } -static UA_StatusCode -verifyApplicationURIAllowAll(void *verificationContext, - const UA_ByteString *certificate, - const UA_String *applicationURI) { +static int UA_OpenSSL_RSA_Key_Size (EVP_PKEY * key){ +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + return EVP_PKEY_get_size (key); +#else + return RSA_size (get_pkey_rsa(key)); +#endif +} + +/* UA_copyCertificate - allocalte the buffer, copy the certificate and + * add a NULL to the end + */ + +UA_StatusCode +UA_copyCertificate (UA_ByteString * dst, + const UA_ByteString * src) { + UA_StatusCode retval = UA_ByteString_allocBuffer (dst, src->length + 1); + if (retval != UA_STATUSCODE_GOOD) + return retval; + (void) memcpy (dst->data, src->data, src->length); + dst->data[dst->length - 1] = '\0'; + dst->length--; + return UA_STATUSCODE_GOOD; } -static void -clearVerifyAllowAll(UA_CertificateVerification *cv) { +static UA_StatusCode +UA_OpenSSL_RSA_Public_Verify (const UA_ByteString * message, + const EVP_MD * evpMd, + X509 * publicKeyX509, + UA_Int16 padding, + const UA_ByteString * signature + ) { + EVP_MD_CTX * mdctx = NULL; + int opensslRet; + EVP_PKEY_CTX * evpKeyCtx; + EVP_PKEY * evpPublicKey = NULL; + UA_StatusCode ret; + mdctx = EVP_MD_CTX_create (); + if (mdctx == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } + evpPublicKey = X509_get_pubkey (publicKeyX509); + if (evpPublicKey == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } + + opensslRet = EVP_DigestVerifyInit (mdctx, &evpKeyCtx, evpMd, NULL, + evpPublicKey); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + EVP_PKEY_CTX_set_rsa_padding (evpKeyCtx, padding); + opensslRet = EVP_DigestVerifyUpdate (mdctx, message->data, message->length); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + opensslRet = EVP_DigestVerifyFinal(mdctx, signature->data, signature->length); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + + ret = UA_STATUSCODE_GOOD; +errout: + if (evpPublicKey != NULL) { + EVP_PKEY_free (evpPublicKey); + } + if (mdctx != NULL) { + EVP_MD_CTX_destroy (mdctx); + } + return ret; } -void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) { - cv->verifyCertificate = verifyCertificateAllowAll; - cv->verifyApplicationURI = verifyApplicationURIAllowAll; - cv->clear = clearVerifyAllowAll; +UA_StatusCode +UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify (const UA_ByteString * msg, + X509 * publicKeyX509, + const UA_ByteString * signature + ) { + return UA_OpenSSL_RSA_Public_Verify (msg, EVP_sha256(), publicKeyX509, + NID_sha256, signature); } -#ifdef UA_ENABLE_ENCRYPTION -/* Find binary substring. Taken and adjusted from - * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */ +/* Get certificate thumbprint, and allocate the buffer. */ -static const unsigned char * -bstrchr(const unsigned char *s, const unsigned char ch, size_t l) { - /* find first occurrence of c in char s[] for length l*/ - /* handle special case */ - if(l == 0) - return (NULL); +UA_StatusCode +UA_Openssl_X509_GetCertificateThumbprint (const UA_ByteString * certficate, + UA_ByteString * pThumbprint, + bool bThumbPrint) { + if (bThumbPrint) { + pThumbprint->length = SHA_DIGEST_LENGTH; + UA_StatusCode ret = UA_ByteString_allocBuffer (pThumbprint, pThumbprint->length); + if (ret != UA_STATUSCODE_GOOD) { + return ret; + } + } + else { + if (pThumbprint->length != SHA_DIGEST_LENGTH) { + return UA_STATUSCODE_BADINTERNALERROR; + } + } + X509 * x509Certificate = UA_OpenSSL_LoadCertificate(certficate); - for(; *s != ch; ++s, --l) - if(l == 0) - return (NULL); - return s; + if (x509Certificate == NULL) { + if (bThumbPrint) { + UA_ByteString_clear (pThumbprint); + } + return UA_STATUSCODE_BADINTERNALERROR; + } + + if (X509_digest (x509Certificate, EVP_sha1(), pThumbprint->data, NULL) + != 1) { + if (bThumbPrint) { + UA_ByteString_clear (pThumbprint); + } + return UA_STATUSCODE_BADINTERNALERROR; + } + X509_free(x509Certificate); + + return UA_STATUSCODE_GOOD; } -const unsigned char * -UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) { - /* find first occurrence of s2[] in s1[] for length l1*/ - const unsigned char *ss1 = s1; - const unsigned char *ss2 = s2; - /* handle special case */ - if(l1 == 0) - return (NULL); - if(l2 == 0) - return s1; +static UA_StatusCode +UA_Openssl_RSA_Private_Decrypt (UA_ByteString * data, + EVP_PKEY * privateKey, + UA_Int16 padding) { + if (data == NULL || privateKey == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - /* match prefix */ - for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL && - (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) { + if (privateKey == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - /* match rest of prefix */ - const unsigned char *sc1, *sc2; - for (sc1 = s1, sc2 = s2; ;) - if (++sc2 >= ss2+l2) - return s1; - else if (*++sc1 != *sc2) - break; + size_t keySize = (size_t) UA_OpenSSL_RSA_Key_Size (privateKey); + size_t cipherOffset = 0; + size_t outOffset = 0; + unsigned char buf[RSA_DECRYPT_BUFFER_LENGTH]; + size_t decryptedBytes; + EVP_PKEY_CTX * ctx; + int opensslRet; + + ctx = EVP_PKEY_CTX_new (privateKey, NULL); + if (ctx == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; } - return NULL; + opensslRet = EVP_PKEY_decrypt_init (ctx); + if (opensslRet != 1) + { + EVP_PKEY_CTX_free (ctx); + return UA_STATUSCODE_BADINTERNALERROR; + } + opensslRet = EVP_PKEY_CTX_set_rsa_padding (ctx, padding); + if (opensslRet != 1) { + EVP_PKEY_CTX_free (ctx); + return UA_STATUSCODE_BADINTERNALERROR; + } + + while (cipherOffset < data->length) { + decryptedBytes = RSA_DECRYPT_BUFFER_LENGTH; + opensslRet = EVP_PKEY_decrypt (ctx, + buf, /* where to decrypt */ + &decryptedBytes, + data->data + cipherOffset, /* what to decrypt */ + keySize + ); + if (opensslRet != 1) { + EVP_PKEY_CTX_free (ctx); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + (void) memcpy(data->data + outOffset, buf, decryptedBytes); + cipherOffset += (size_t) keySize; + outOffset += decryptedBytes; + } + data->length = outOffset; + EVP_PKEY_CTX_free (ctx); + + return UA_STATUSCODE_GOOD; } -#endif /* end of UA_ENABLE_ENCRYPTION */ -#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS +UA_StatusCode +UA_Openssl_RSA_Oaep_Decrypt (UA_ByteString * data, + EVP_PKEY * privateKey) { + return UA_Openssl_RSA_Private_Decrypt (data, privateKey, + RSA_PKCS1_OAEP_PADDING); +} -// mbedTLS expects PEM data to be null terminated -// The data length parameter must include the null terminator -static UA_ByteString copyDataFormatAware(const UA_ByteString *data) -{ - UA_ByteString result; - UA_ByteString_init(&result); +static UA_StatusCode +UA_Openssl_RSA_Public_Encrypt (const UA_ByteString * message, + X509 * publicX509, + UA_Int16 padding, + size_t paddingSize, + UA_ByteString * encrypted) { + EVP_PKEY_CTX * ctx = NULL; + EVP_PKEY * evpPublicKey = NULL; + int opensslRet; + UA_StatusCode ret; + size_t encryptedTextLen = 0; + size_t dataPos = 0; + size_t encryptedPos = 0; + size_t bytesToEncrypt = 0; + size_t encryptedBlockSize = 0; + size_t keySize = 0; - if (!data->length) - return result; + evpPublicKey = X509_get_pubkey (publicX509); + if (evpPublicKey == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } + ctx = EVP_PKEY_CTX_new (evpPublicKey, NULL); + if (ctx == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } + opensslRet = EVP_PKEY_encrypt_init (ctx); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + opensslRet = EVP_PKEY_CTX_set_rsa_padding (ctx, padding); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } - if (data->length && data->data[0] == '-') { - UA_ByteString_allocBuffer(&result, data->length + 1); - memcpy(result.data, data->data, data->length); - result.data[data->length] = '\0'; - } else { - UA_ByteString_copy(data, &result); + /* get the encrypted block size */ + + keySize = (size_t) UA_OpenSSL_RSA_Key_Size (evpPublicKey); + if (keySize == 0) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; } - return result; + switch (padding) { + case RSA_PKCS1_OAEP_PADDING: + case RSA_PKCS1_PADDING: + if (keySize <= paddingSize) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + encryptedBlockSize = keySize - paddingSize; + break; + default: + ret = UA_STATUSCODE_BADNOTSUPPORTED; + goto errout; + break; + } + + /* encrypt in reverse order so that [data] may alias [encrypted] */ + + dataPos = message->length; + encryptedPos = ((dataPos - 1) / encryptedBlockSize + 1) * keySize; + bytesToEncrypt = (dataPos - 1) % encryptedBlockSize + 1; + encryptedTextLen = encryptedPos; + + while (dataPos > 0) { + size_t outlen = keySize; + encryptedPos -= keySize; + dataPos -= bytesToEncrypt; + opensslRet = EVP_PKEY_encrypt (ctx, encrypted->data + encryptedPos, &outlen, + message->data + dataPos, bytesToEncrypt); + + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + bytesToEncrypt = encryptedBlockSize; + } + encrypted->length = encryptedTextLen; + + ret = UA_STATUSCODE_GOOD; +errout: + if (evpPublicKey != NULL) { + EVP_PKEY_free (evpPublicKey); + } + if (ctx != NULL) { + EVP_PKEY_CTX_free (ctx); + } + return ret; } -typedef struct { - /* If the folders are defined, we use them to reload the certificates during - * runtime */ - UA_String trustListFolder; - UA_String issuerListFolder; - UA_String revocationListFolder; +UA_StatusCode +UA_Openssl_RSA_OAEP_Encrypt (UA_ByteString * data, + size_t paddingSize, + X509 * publicX509) { + UA_ByteString message; + UA_StatusCode ret; - mbedtls_x509_crt certificateTrustList; - mbedtls_x509_crt certificateIssuerList; - mbedtls_x509_crl certificateRevocationList; -} CertInfo; + ret = UA_ByteString_copy (data, &message); + if (ret != UA_STATUSCODE_GOOD) { + return ret; + } + ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509, + RSA_PKCS1_OAEP_PADDING, + paddingSize, + data); + UA_ByteString_clear (&message); + return ret; +} -#ifdef __linux__ /* Linux only so far */ +static UA_Openssl_P_SHA256_Ctx * +P_SHA256_Ctx_Create (const UA_ByteString * secret, + const UA_ByteString * seed) { + size_t size = (UA_Int32)sizeof (UA_Openssl_P_SHA256_Ctx) + secret->length + + seed->length; + UA_Openssl_P_SHA256_Ctx * ctx = (UA_Openssl_P_SHA256_Ctx *) UA_malloc (size); + if (ctx == NULL) { + return NULL; + } + ctx->secretLen = secret->length; + ctx->seedLen = seed->length; + (void) memcpy (UA_Openssl_P_SHA256_SEED(ctx), seed->data, seed->length); + (void) memcpy (UA_Openssl_P_SHA256_SECRET(ctx), secret->data, secret->length); + /* A(0) = seed + A(n) = HMAC_HASH(secret, A(n-1)) */ -#include <dirent.h> -#include <limits.h> + if (HMAC (EVP_sha256(), secret->data, (int) secret->length, seed->data, + seed->length, ctx->A, NULL) == NULL) { + UA_free (ctx); + return NULL; + } + + return ctx; +} static UA_StatusCode -fileNamesFromFolder(const UA_String *folder, size_t *pathsSize, UA_String **paths) { - char buf[PATH_MAX + 1]; - if(folder->length > PATH_MAX) - return UA_STATUSCODE_BADINTERNALERROR; +P_SHA256_Hash_Generate (UA_Openssl_P_SHA256_Ctx * ctx, + UA_Byte * pHas + ) { + /* Calculate P_SHA256(n) = HMAC_SHA256(secret, A(n)+seed) */ + if (HMAC (EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen, + ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } - memcpy(buf, folder->data, folder->length); - buf[folder->length] = 0; - - DIR *dir = opendir(buf); - if(!dir) - return UA_STATUSCODE_BADINTERNALERROR; + /* Calculate A(n) = HMAC_SHA256(secret, A(n-1)) */ + if (HMAC (EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen, + ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} - *paths = (UA_String*)UA_Array_new(256, &UA_TYPES[UA_TYPES_STRING]); - if(*paths == NULL) { - closedir(dir); +UA_StatusCode +UA_Openssl_Random_Key_PSHA256_Derive (const UA_ByteString * secret, + const UA_ByteString * seed, + UA_ByteString * out) { + size_t keyLen = out->length; + size_t iter = keyLen/32 + ((keyLen%32)?1:0); + size_t bufferLen = iter * 32; + size_t i; + UA_StatusCode st; + + UA_Byte * pBuffer = (UA_Byte *) UA_malloc (bufferLen); + if (pBuffer == NULL) { return UA_STATUSCODE_BADOUTOFMEMORY; } - struct dirent *ent; - char buf2[PATH_MAX + 1]; - char *res = realpath(buf, buf2); - if(!res) { - closedir(dir); - return UA_STATUSCODE_BADINTERNALERROR; + UA_Openssl_P_SHA256_Ctx * ctx = P_SHA256_Ctx_Create (secret, seed); + if (ctx == NULL) { + UA_free (pBuffer); + return UA_STATUSCODE_BADOUTOFMEMORY; } - size_t pathlen = strlen(buf2); - *pathsSize = 0; - while((ent = readdir (dir)) != NULL && *pathsSize < 256) { - if(ent->d_type != DT_REG) - continue; - buf2[pathlen] = '/'; - buf2[pathlen+1] = 0; - strcat(buf2, ent->d_name); - (*paths)[*pathsSize] = UA_STRING_ALLOC(buf2); - *pathsSize += 1; + + for (i = 0; i < iter; i++) { + st = P_SHA256_Hash_Generate (ctx, pBuffer + (i * 32)); + if (st != UA_STATUSCODE_GOOD) { + UA_free (pBuffer); + UA_free (ctx); + return st; + } } - closedir(dir); - if(*pathsSize == 0) { - UA_free(*paths); - *paths = NULL; + (void) memcpy (out->data, pBuffer, keyLen); + UA_free (pBuffer); + UA_free (ctx); + return UA_STATUSCODE_GOOD; +} + +/* return the key bytes */ +UA_StatusCode +UA_Openssl_RSA_Public_GetKeyLength (X509 * publicKeyX509, + UA_Int32 * keyLen) { + EVP_PKEY * evpKey = X509_get_pubkey (publicKeyX509); + if (evpKey == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + *keyLen = UA_OpenSSL_RSA_Key_Size (evpKey); + + EVP_PKEY_free (evpKey); + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Openssl_RSA_Private_GetKeyLength (EVP_PKEY * privateKey, + UA_Int32 * keyLen) { + if (privateKey == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } + *keyLen = UA_OpenSSL_RSA_Key_Size (privateKey); + return UA_STATUSCODE_GOOD; } static UA_StatusCode -reloadCertificates(CertInfo *ci) { - UA_StatusCode retval = UA_STATUSCODE_GOOD; - int err = 0; +UA_Openssl_RSA_Private_Sign (const UA_ByteString * message, + EVP_PKEY * privateKey, + const EVP_MD * evpMd, + UA_Int16 padding, + UA_ByteString * outSignature) { + EVP_MD_CTX * mdctx = NULL; + int opensslRet; + EVP_PKEY_CTX * evpKeyCtx; + UA_StatusCode ret; - /* Load the trustlists */ - if(ci->trustListFolder.length > 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list"); - mbedtls_x509_crt_free(&ci->certificateTrustList); - mbedtls_x509_crt_init(&ci->certificateTrustList); + mdctx = EVP_MD_CTX_create (); + if (mdctx == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } - char f[PATH_MAX]; - memcpy(f, ci->trustListFolder.data, ci->trustListFolder.length); - f[ci->trustListFolder.length] = 0; - err = mbedtls_x509_crt_parse_path(&ci->certificateTrustList, f); - if(err == 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Loaded certificate from %s", f); - } else { - char errBuff[300]; - mbedtls_strerror(err, errBuff, 300); - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to load certificate from %s", f); - } + if (privateKey == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } + opensslRet = EVP_DigestSignInit (mdctx, &evpKeyCtx, evpMd, NULL, privateKey); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + EVP_PKEY_CTX_set_rsa_padding (evpKeyCtx, padding); - /* Load the revocationlists */ - if(ci->revocationListFolder.length > 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list"); - size_t pathsSize = 0; - UA_String *paths = NULL; - retval = fileNamesFromFolder(&ci->revocationListFolder, &pathsSize, &paths); - if(retval != UA_STATUSCODE_GOOD) - return retval; - mbedtls_x509_crl_free(&ci->certificateRevocationList); - mbedtls_x509_crl_init(&ci->certificateRevocationList); - for(size_t i = 0; i < pathsSize; i++) { - char f[PATH_MAX]; - memcpy(f, paths[i].data, paths[i].length); - f[paths[i].length] = 0; - err = mbedtls_x509_crl_parse_file(&ci->certificateRevocationList, f); - if(err == 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Loaded certificate from %.*s", - (int)paths[i].length, paths[i].data); - } else { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to load certificate from %.*s", - (int)paths[i].length, paths[i].data); - } - } - UA_Array_delete(paths, pathsSize, &UA_TYPES[UA_TYPES_STRING]); - paths = NULL; - pathsSize = 0; + opensslRet = EVP_DigestSignUpdate (mdctx, message->data, message->length); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + opensslRet = EVP_DigestSignFinal (mdctx, outSignature->data, &outSignature->length); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; } - /* Load the issuerlists */ - if(ci->issuerListFolder.length > 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list"); - mbedtls_x509_crt_free(&ci->certificateIssuerList); - mbedtls_x509_crt_init(&ci->certificateIssuerList); - char f[PATH_MAX]; - memcpy(f, ci->issuerListFolder.data, ci->issuerListFolder.length); - f[ci->issuerListFolder.length] = 0; - err = mbedtls_x509_crt_parse_path(&ci->certificateIssuerList, f); - if(err == 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Loaded certificate from %s", f); - } else { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to load certificate from %s", f); - } + ret = UA_STATUSCODE_GOOD; +errout: + if (mdctx != NULL) { + EVP_MD_CTX_destroy (mdctx); } + return ret; +} - return retval; +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_SHA256_Sign (const UA_ByteString * message, + EVP_PKEY * privateKey, + UA_ByteString * outSignature) { + return UA_Openssl_RSA_Private_Sign (message, privateKey, EVP_sha256(), + NID_sha256, outSignature); } -#endif +UA_StatusCode +UA_OpenSSL_HMAC_SHA256_Verify (const UA_ByteString * message, + const UA_ByteString * key, + const UA_ByteString * signature + ) { + unsigned char buf[SHA256_DIGEST_LENGTH] = {0}; + UA_ByteString mac = {SHA256_DIGEST_LENGTH, buf}; -static UA_StatusCode -certificateVerification_verify(void *verificationContext, - const UA_ByteString *certificate) { - CertInfo *ci = (CertInfo*)verificationContext; - if(!ci) + if (HMAC (EVP_sha256(), key->data, (int) key->length, message->data, message->length, + mac.data, (unsigned int *) &mac.length) == NULL) { return UA_STATUSCODE_BADINTERNALERROR; - -#ifdef __linux__ /* Reload certificates if folder paths are specified */ - reloadCertificates(ci); -#endif - - if(ci->trustListFolder.length == 0 && - ci->issuerListFolder.length == 0 && - ci->revocationListFolder.length == 0 && - ci->certificateTrustList.raw.len == 0 && - ci->certificateIssuerList.raw.len == 0 && - ci->certificateRevocationList.raw.len == 0) { - UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "PKI plugin unconfigured. Accepting the certificate."); + } + if (UA_ByteString_equal (signature, &mac)) { return UA_STATUSCODE_GOOD; } + else { + return UA_STATUSCODE_BADINTERNALERROR; + } +} - /* Parse the certificate */ - mbedtls_x509_crt remoteCertificate; +UA_StatusCode +UA_OpenSSL_HMAC_SHA256_Sign (const UA_ByteString * message, + const UA_ByteString * key, + UA_ByteString * signature + ) { + if (HMAC (EVP_sha256(), key->data, (int) key->length, message->data, + message->length, + signature->data, (unsigned int *) &(signature->length)) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} - /* Temporary Object to parse the trustList */ - mbedtls_x509_crt *tempCert = NULL; +static UA_StatusCode +UA_OpenSSL_Decrypt (const UA_ByteString * iv, + const UA_ByteString * key, + const EVP_CIPHER * cipherAlg, + UA_ByteString * data /* [in/out]*/) { + UA_ByteString ivCopy = {0, NULL}; + UA_ByteString cipherTxt = {0, NULL}; + EVP_CIPHER_CTX * ctx = NULL; + UA_StatusCode ret; + int opensslRet; + int outLen; + int tmpLen; - /* Temporary Object to parse the revocationList */ - mbedtls_x509_crl *tempCrl = NULL; + /* copy the IV because the AES_cbc_encrypt function overwrites it. */ - /* Temporary Object to identify the parent CA when there is no intermediate CA */ - mbedtls_x509_crt *parentCert = NULL; + ret = UA_ByteString_copy (iv, &ivCopy); + if (ret != UA_STATUSCODE_GOOD) { + goto errout; + } - /* Temporary Object to identify the parent CA when there is intermediate CA */ - mbedtls_x509_crt *parentCert_2 = NULL; + ret = UA_ByteString_copy (data, &cipherTxt); + if (ret != UA_STATUSCODE_GOOD) { + goto errout; + } - /* Flag value to identify if the issuer certificate is found */ - int issuerKnown = 0; + ctx = EVP_CIPHER_CTX_new (); + if (ctx == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } - /* Flag value to identify if the parent certificate found */ - int parentFound = 0; + /* call EVP_* to decrypt */ - mbedtls_x509_crt_init(&remoteCertificate); - int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data, - certificate->length); - if(mbedErr) { - /* char errBuff[300]; */ - /* mbedtls_strerror(mbedErr, errBuff, 300); */ - /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */ - /* "Could not parse the remote certificate with error: %s", errBuff); */ - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + opensslRet = EVP_DecryptInit_ex (ctx, cipherAlg, NULL, key->data, ivCopy.data); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; } + /* EVP_DecryptFinal() will return an error code if padding is enabled + * and the final block is not correctly formatted. + */ + EVP_CIPHER_CTX_set_padding (ctx, 0); + opensslRet = EVP_DecryptUpdate (ctx, data->data, &outLen, + cipherTxt.data, (int) cipherTxt.length); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + opensslRet = EVP_DecryptFinal_ex (ctx, data->data + outLen, &tmpLen); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + outLen += tmpLen; + data->length = (size_t) outLen; + ret = UA_STATUSCODE_GOOD; - /* Verify */ - mbedtls_x509_crt_profile crtProfile = { - MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256), - 0xFFFFFF, 0x000000, 128 * 8 // in bits - }; // TODO: remove magic numbers +errout: + UA_ByteString_clear (&ivCopy); + UA_ByteString_clear (&cipherTxt); + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + return ret; +} - uint32_t flags = 0; - mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, - &ci->certificateTrustList, - &ci->certificateRevocationList, - &crtProfile, NULL, &flags, NULL, NULL); +static UA_StatusCode +UA_OpenSSL_Encrypt (const UA_ByteString * iv, + const UA_ByteString * key, + const EVP_CIPHER * cipherAlg, + UA_ByteString * data /* [in/out]*/ + ) { - /* Flag to check if the remote certificate is trusted or not */ - int TRUSTED = 0; + UA_ByteString ivCopy = {0, NULL}; + UA_ByteString plainTxt = {0, NULL}; + EVP_CIPHER_CTX * ctx = NULL; + UA_StatusCode ret; + int opensslRet; + int outLen; + int tmpLen; - /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */ - if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) { - for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) { - if(remoteCertificate.raw.len == tempCert->raw.len && - memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) { - TRUSTED = REMOTECERTIFICATETRUSTED; - break; - } - } + /* copy the IV because the AES_cbc_encrypt function overwrites it. */ + + ret = UA_ByteString_copy (iv, &ivCopy); + if (ret != UA_STATUSCODE_GOOD) { + goto errout; } - /* If the remote certificate is present in the trustList then check if the issuer certificate - * of remoteCertificate is present in issuerList */ - if(TRUSTED && mbedErr) { - mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, - &ci->certificateIssuerList, - &ci->certificateRevocationList, - &crtProfile, NULL, &flags, NULL, NULL); + ret = UA_ByteString_copy (data, &plainTxt); + if (ret != UA_STATUSCODE_GOOD) { + goto errout; + } - /* Check if the parent certificate has a CRL file available */ - if(!mbedErr) { - /* Flag value to identify if that there is an intermediate CA present */ - int dualParent = 0; + ctx = EVP_CIPHER_CTX_new (); + if (ctx == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto errout; + } - /* Identify the topmost parent certificate for the remoteCertificate */ - for( parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) { - if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) { - for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) { - if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) { - dualParent = DUALPARENT; - parentFound = PARENTFOUND; - break; - } + /* call EVP_* to encrypt */ - } + opensslRet = EVP_EncryptInit_ex (ctx, cipherAlg, NULL, key->data, ivCopy.data); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + opensslRet = EVP_EncryptUpdate (ctx, data->data, &outLen, + plainTxt.data, (int) plainTxt.length); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + /* + * Buffer passed to EVP_EncryptFinal() must be after data just + * encrypted to avoid overwriting it. + */ + opensslRet = EVP_EncryptFinal_ex(ctx, data->data + outLen, &tmpLen); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + outLen += tmpLen; + data->length = (size_t) outLen; + ret = UA_STATUSCODE_GOOD; - parentFound = PARENTFOUND; - } +errout: + UA_ByteString_clear (&ivCopy); + UA_ByteString_clear (&plainTxt); + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + return ret; +} - if(parentFound == PARENTFOUND) { - break; - } +UA_StatusCode +UA_OpenSSL_AES_256_CBC_Decrypt (const UA_ByteString * iv, + const UA_ByteString * key, + UA_ByteString * data /* [in/out]*/ + ) { + return UA_OpenSSL_Decrypt (iv, key, EVP_aes_256_cbc (), data); +} - } +UA_StatusCode +UA_OpenSSL_AES_256_CBC_Encrypt (const UA_ByteString * iv, + const UA_ByteString * key, + UA_ByteString * data /* [in/out]*/ + ) { + return UA_OpenSSL_Encrypt (iv, key, EVP_aes_256_cbc (), data); +} - /* Check if there is an intermediate certificate between the topmost parent - * certificate and child certificate - * If yes the topmost parent certificate is to be checked whether it has a - * CRL file avaiable */ - if(dualParent == DUALPARENT && parentFound == PARENTFOUND) { - parentCert = parentCert_2; - } +UA_StatusCode +UA_OpenSSL_X509_compare (const UA_ByteString * cert, + const X509 * bcert) { + X509 * acert = UA_OpenSSL_LoadCertificate(cert); + if (acert == NULL) { + return UA_STATUSCODE_BADCERTIFICATEINVALID; + } + int opensslRet = X509_cmp (acert, bcert); + X509_free (acert); - /* If a parent certificate is found traverse the revocationList and identify - * if there is any CRL file that corresponds to the parentCertificate */ - if(parentFound == PARENTFOUND) { - tempCrl = &ci->certificateRevocationList; - while(tempCrl != NULL) { - if(tempCrl->version != 0 && - tempCrl->issuer_raw.len == parentCert->subject_raw.len && - memcmp(tempCrl->issuer_raw.p, - parentCert->subject_raw.p, - tempCrl->issuer_raw.len) == 0) { - issuerKnown = ISSUERKNOWN; - break; - } + if (opensslRet == 0) + return UA_STATUSCODE_GOOD; + return UA_STATUSCODE_UNCERTAINSUBNORMAL; +} - tempCrl = tempCrl->next; - } +UA_StatusCode +UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (const UA_ByteString * msg, + X509 * publicKeyX509, + const UA_ByteString * signature) { + return UA_OpenSSL_RSA_Public_Verify (msg, EVP_sha1(), publicKeyX509, + NID_sha1, signature); +} - /* If the CRL file corresponding to the parent certificate is not present - * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */ - if(!issuerKnown) { - return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; - } +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (const UA_ByteString * message, + EVP_PKEY * privateKey, + UA_ByteString * outSignature) { + return UA_Openssl_RSA_Private_Sign (message, privateKey, EVP_sha1(), + NID_sha1, outSignature); +} - } +static UA_Openssl_P_SHA1_Ctx * +P_SHA1_Ctx_Create (const UA_ByteString * secret, + const UA_ByteString * seed) { + size_t size = (UA_Int32)sizeof (UA_Openssl_P_SHA1_Ctx) + secret->length + + seed->length; + UA_Openssl_P_SHA1_Ctx * ctx = (UA_Openssl_P_SHA1_Ctx *) UA_malloc (size); + if (ctx == NULL) { + return NULL; + } - } + ctx->secretLen = secret->length; + ctx->seedLen = seed->length; + (void) memcpy (UA_Openssl_P_SHA1_SEED(ctx), seed->data, seed->length); + (void) memcpy (UA_Openssl_P_SHA1_SECRET(ctx), secret->data, secret->length); + /* A(0) = seed + A(n) = HMAC_HASH(secret, A(n-1)) */ + if (HMAC (EVP_sha1(), secret->data, (int) secret->length, seed->data, + seed->length, ctx->A, NULL) == NULL) { + UA_free (ctx); + return NULL; } - else if(!mbedErr && !TRUSTED) { - /* This else if section is to identify if the parent certificate which is present in trustList - * has CRL file corresponding to it */ - /* Identify the parent certificate of the remoteCertificate */ - for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) { - if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) { - parentFound = PARENTFOUND; - break; - } + return ctx; +} +static UA_StatusCode +P_SHA1_Hash_Generate (UA_Openssl_P_SHA1_Ctx * ctx, + UA_Byte * pHas + ) { + /* Calculate P_SHA1(n) = HMAC_SHA1(secret, A(n)+seed) */ + if (HMAC (EVP_sha1 (), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen, + ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; } - /* If the parent certificate is found traverse the revocationList and identify - * if there is any CRL file that corresponds to the parentCertificate */ - if(parentFound == PARENTFOUND && - memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) { - tempCrl = &ci->certificateRevocationList; - while(tempCrl != NULL) { - if(tempCrl->version != 0 && - tempCrl->issuer_raw.len == parentCert->subject_raw.len && - memcmp(tempCrl->issuer_raw.p, - parentCert->subject_raw.p, - tempCrl->issuer_raw.len) == 0) { - issuerKnown = ISSUERKNOWN; - break; - } - - tempCrl = tempCrl->next; - } - - /* If the CRL file corresponding to the parent certificate is not present - * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */ - if(!issuerKnown) { - return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; - } - + /* Calculate A(n) = HMAC_SHA1(secret, A(n-1)) */ + if (HMAC (EVP_sha1(), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen, + ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; } + return UA_STATUSCODE_GOOD; +} +UA_StatusCode +UA_Openssl_Random_Key_PSHA1_Derive (const UA_ByteString * secret, + const UA_ByteString * seed, + UA_ByteString * out) { + size_t keyLen = out->length; + size_t iter = keyLen / SHA1_DIGEST_LENGTH + ((keyLen % SHA1_DIGEST_LENGTH)?1:0); + size_t bufferLen = iter * SHA1_DIGEST_LENGTH; + UA_Byte * pBuffer = (UA_Byte *) UA_malloc (bufferLen); + if (pBuffer == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; } - // TODO: Extend verification - - /* This condition will check whether the certificate is a User certificate - * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and - * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate - * shall be condidered as CA Certificate and cannot be used to establish a - * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js - * for more details */ - if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) && - (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) { - return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; + UA_Openssl_P_SHA1_Ctx * ctx = P_SHA1_Ctx_Create (secret, seed); + if (ctx == NULL) { + UA_free (pBuffer); + return UA_STATUSCODE_BADOUTOFMEMORY; } - UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(mbedErr) { -#if UA_LOGLEVEL <= 400 - char buff[100]; - int len = mbedtls_x509_crt_verify_info(buff, 100, "", flags); - UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, - "Verifying the certificate failed with error: %.*s", len-1, buff); -#endif - if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) { - retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; - } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE || - flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) { - retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; - } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED || - flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) { - retval = UA_STATUSCODE_BADCERTIFICATEREVOKED; - } else { - retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + size_t i; + UA_StatusCode st; + + for (i = 0; i < iter; i++) { + st = P_SHA1_Hash_Generate (ctx, pBuffer + (i * SHA1_DIGEST_LENGTH)); + if (st != UA_STATUSCODE_GOOD) { + UA_free (pBuffer); + UA_free (ctx); + return st; } } - mbedtls_x509_crt_free(&remoteCertificate); - return retval; + (void) memcpy (out->data, pBuffer, keyLen); + UA_free (pBuffer); + UA_free (ctx); + + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -certificateVerification_verifyApplicationURI(void *verificationContext, - const UA_ByteString *certificate, - const UA_String *applicationURI) { - CertInfo *ci = (CertInfo*)verificationContext; - if(!ci) +UA_StatusCode +UA_OpenSSL_HMAC_SHA1_Verify (const UA_ByteString * message, + const UA_ByteString * key, + const UA_ByteString * signature + ) { + unsigned char buf[SHA1_DIGEST_LENGTH] = {0}; + UA_ByteString mac = {SHA1_DIGEST_LENGTH, buf}; + + if(HMAC (EVP_sha1(), key->data, (int) key->length, message->data, message->length, + mac.data, (unsigned int *) &mac.length) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + if (UA_ByteString_equal (signature, &mac)) { + return UA_STATUSCODE_GOOD; + } + else { return UA_STATUSCODE_BADINTERNALERROR; + } +} - /* Parse the certificate */ - mbedtls_x509_crt remoteCertificate; - mbedtls_x509_crt_init(&remoteCertificate); - int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data, - certificate->length); - if(mbedErr) - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; +UA_StatusCode +UA_OpenSSL_HMAC_SHA1_Sign (const UA_ByteString * message, + const UA_ByteString * key, + UA_ByteString * signature + ) { + if (HMAC (EVP_sha1(), key->data, (int) key->length, message->data, + message->length, + signature->data, (unsigned int *) &(signature->length)) == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} - /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields - * of the Alternative Subject Name. Instead test whether the URI-string is - * present in the v3_ext field in general. - * - * TODO: Improve parsing of the Alternative Subject Name */ - UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(UA_Bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len, - applicationURI->data, applicationURI->length) == NULL) - retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID; +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_Decrypt (UA_ByteString * data, + EVP_PKEY * privateKey) { + return UA_Openssl_RSA_Private_Decrypt (data, privateKey, + RSA_PKCS1_PADDING); +} - mbedtls_x509_crt_free(&remoteCertificate); - return retval; +UA_StatusCode +UA_Openssl_RSA_PKCS1_V15_Encrypt (UA_ByteString * data, + size_t paddingSize, + X509 * publicX509) { + UA_ByteString message; + UA_StatusCode ret = UA_ByteString_copy (data, &message); + if (ret != UA_STATUSCODE_GOOD) { + return ret; + } + ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509, + RSA_PKCS1_PADDING, + paddingSize, + data); + UA_ByteString_clear (&message); + return ret; } -static void -certificateVerification_clear(UA_CertificateVerification *cv) { - CertInfo *ci = (CertInfo*)cv->context; - if(!ci) - return; - mbedtls_x509_crt_free(&ci->certificateTrustList); - mbedtls_x509_crl_free(&ci->certificateRevocationList); - mbedtls_x509_crt_free(&ci->certificateIssuerList); - UA_String_clear(&ci->trustListFolder); - UA_String_clear(&ci->issuerListFolder); - UA_String_clear(&ci->revocationListFolder); - UA_free(ci); - cv->context = NULL; +UA_StatusCode +UA_OpenSSL_AES_128_CBC_Decrypt (const UA_ByteString * iv, + const UA_ByteString * key, + UA_ByteString * data /* [in/out]*/ + ) { + return UA_OpenSSL_Decrypt (iv, key, EVP_aes_128_cbc (), data); } UA_StatusCode -UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv, - const UA_ByteString *certificateTrustList, - size_t certificateTrustListSize, - const UA_ByteString *certificateIssuerList, - size_t certificateIssuerListSize, - const UA_ByteString *certificateRevocationList, - size_t certificateRevocationListSize) { - CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo)); - if(!ci) - return UA_STATUSCODE_BADOUTOFMEMORY; - memset(ci, 0, sizeof(CertInfo)); - mbedtls_x509_crt_init(&ci->certificateTrustList); - mbedtls_x509_crl_init(&ci->certificateRevocationList); - mbedtls_x509_crt_init(&ci->certificateIssuerList); +UA_OpenSSL_AES_128_CBC_Encrypt (const UA_ByteString * iv, + const UA_ByteString * key, + UA_ByteString * data /* [in/out]*/ + ) { + return UA_OpenSSL_Encrypt (iv, key, EVP_aes_128_cbc (), data); +} - cv->context = (void*)ci; - if(certificateTrustListSize > 0) - cv->verifyCertificate = certificateVerification_verify; - else - cv->verifyCertificate = verifyCertificateAllowAll; - cv->clear = certificateVerification_clear; - cv->verifyApplicationURI = certificateVerification_verifyApplicationURI; +EVP_PKEY * +UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey) { + const unsigned char * pkData = privateKey->data; + long len = (long) privateKey->length; - int err = 0; - UA_ByteString data; - UA_ByteString_init(&data); + EVP_PKEY *result = NULL; - for(size_t i = 0; i < certificateTrustListSize; i++) { - data = copyDataFormatAware(&certificateTrustList[i]); - err = mbedtls_x509_crt_parse(&ci->certificateTrustList, - data.data, - data.length); - UA_ByteString_clear(&data); - if(err) - goto error; - } - for(size_t i = 0; i < certificateIssuerListSize; i++) { - data = copyDataFormatAware(&certificateIssuerList[i]); - err = mbedtls_x509_crt_parse(&ci->certificateIssuerList, - data.data, - data.length); - UA_ByteString_clear(&data); - if(err) - goto error; + if (len > 1 && pkData[0] == 0x30 && pkData[1] == 0x82) { // Magic number for DER encoded keys + result = d2i_PrivateKey(EVP_PKEY_RSA, NULL, + &pkData, len); + } else { + BIO *bio = NULL; + bio = BIO_new_mem_buf((void *) privateKey->data, (int) privateKey->length); + result = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + BIO_free(bio); } - for(size_t i = 0; i < certificateRevocationListSize; i++) { - data = copyDataFormatAware(&certificateRevocationList[i]); - err = mbedtls_x509_crl_parse(&ci->certificateRevocationList, - data.data, - data.length); - UA_ByteString_clear(&data); - if(err) - goto error; + + return result; +} + +X509 * +UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate) { + X509 * result = NULL; + const unsigned char *pData = certificate->data; + + if (certificate->length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files + result = UA_OpenSSL_LoadDerCertificate(certificate); + } else { + result = UA_OpenSSL_LoadPemCertificate(certificate); } - return UA_STATUSCODE_GOOD; -error: - certificateVerification_clear(cv); - return UA_STATUSCODE_BADINTERNALERROR; + return result; } -#ifdef __linux__ /* Linux only so far */ +X509 * +UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate) { + const unsigned char *pData = certificate->data; + return d2i_X509(NULL, &pData, (long) certificate->length); +} + +X509 * +UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate) { + X509 * result = NULL; + + BIO* bio = NULL; + bio = BIO_new_mem_buf((void *) certificate->data, (int) certificate->length); + result = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + + return result; +} UA_StatusCode -UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv, - const char *trustListFolder, - const char *issuerListFolder, - const char *revocationListFolder) { - CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo)); - if(!ci) - return UA_STATUSCODE_BADOUTOFMEMORY; - memset(ci, 0, sizeof(CertInfo)); - mbedtls_x509_crt_init(&ci->certificateTrustList); - mbedtls_x509_crl_init(&ci->certificateRevocationList); - mbedtls_x509_crt_init(&ci->certificateIssuerList); +UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString *target) { + X509 *cert = UA_OpenSSL_LoadCertificate(certificate); - /* Only set the folder paths. They will be reloaded during runtime. - * TODO: Add a more efficient reloading of only the changes */ - ci->trustListFolder = UA_STRING_ALLOC(trustListFolder); - ci->issuerListFolder = UA_STRING_ALLOC(issuerListFolder); - ci->revocationListFolder = UA_STRING_ALLOC(revocationListFolder); + if (!cert) { + UA_ByteString_init(target); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - reloadCertificates(ci); + unsigned char *derData = NULL; + int length = i2d_X509(cert, &derData); + X509_free(cert); - cv->context = (void*)ci; - cv->verifyCertificate = certificateVerification_verify; - cv->clear = certificateVerification_clear; - cv->verifyApplicationURI = certificateVerification_verifyApplicationURI; + if (length > 0) { + UA_ByteString temp; + temp.length = (size_t) length; + temp.data = derData; + UA_ByteString_copy(&temp, target); + OPENSSL_free(derData); + return UA_STATUSCODE_GOOD; + } else { + UA_ByteString_init(target); + } - return UA_STATUSCODE_GOOD; + return UA_STATUSCODE_BADINVALIDARGUMENT; } #endif -#endif - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_nodestore_ziptree.c" ***********************************/ +/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_basic128rsa15.c" ****/ -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2017 (c) Julian Grothoff - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2020 (c) Wind River Systems, Inc. + * Copyright 2020 (c) basysKom GmbH */ -#ifndef container_of -#define container_of(ptr, type, member) \ - (type *)((uintptr_t)ptr - offsetof(type,member)) -#endif +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) -struct NodeEntry; -typedef struct NodeEntry NodeEntry; -struct NodeEntry { - ZIP_ENTRY(NodeEntry) zipfields; - UA_UInt32 nodeIdHash; - UA_UInt16 refCount; /* How many consumers have a reference to the node? */ - UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */ - NodeEntry *orig; /* If a copy is made to replace a node, track that we - * replace only the node from which the copy was made. - * Important for concurrent operations. */ - UA_NodeId nodeId; /* This is actually a UA_Node that also starts with a NodeId */ -}; +#include <openssl/x509.h> +#include <openssl/rand.h> +#include <openssl/evp.h> -/* Absolute ordering for NodeIds */ -static enum ZIP_CMP -cmpNodeId(const void *a, const void *b) { - const NodeEntry *aa = (const NodeEntry*)a; - const NodeEntry *bb = (const NodeEntry*)b; +#define UA_SHA1_LENGTH 20 +#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN 11 +#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH 16 +#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH 16 +#define UA_SHA1_LENGTH 20 - /* Compare hash */ - if(aa->nodeIdHash < bb->nodeIdHash) - return ZIP_CMP_LESS; - if(aa->nodeIdHash > bb->nodeIdHash) - return ZIP_CMP_MORE; +typedef struct { + EVP_PKEY * localPrivateKey; + UA_ByteString localCertThumbprint; + const UA_Logger * logger; +} Policy_Context_Basic128Rsa15; - /* Compore nodes in detail */ - return (enum ZIP_CMP)UA_NodeId_order(&aa->nodeId, &bb->nodeId); -} +typedef struct { + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; -ZIP_HEAD(NodeTree, NodeEntry); -typedef struct NodeTree NodeTree; + Policy_Context_Basic128Rsa15 * policyContext; + UA_ByteString remoteCertificate; + X509 * remoteCertificateX509; +} Channel_Context_Basic128Rsa15; -typedef struct { - NodeTree root; -} ZipContext; +static UA_StatusCode +UA_Policy_Basic128Rsa15_New_Context (UA_SecurityPolicy * securityPolicy, + const UA_ByteString localPrivateKey, + const UA_Logger * logger) { + Policy_Context_Basic128Rsa15 * context = (Policy_Context_Basic128Rsa15 *) + UA_malloc (sizeof (Policy_Context_Basic128Rsa15)); + if (context == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); -ZIP_PROTTYPE(NodeTree, NodeEntry, NodeEntry) -ZIP_IMPL(NodeTree, NodeEntry, zipfields, NodeEntry, zipfields, cmpNodeId) + if (!context->localPrivateKey) { + UA_free(context); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } -static NodeEntry * -newEntry(UA_NodeClass nodeClass) { - size_t size = sizeof(NodeEntry) - sizeof(UA_NodeId); - switch(nodeClass) { - case UA_NODECLASS_OBJECT: - size += sizeof(UA_ObjectNode); - break; - case UA_NODECLASS_VARIABLE: - size += sizeof(UA_VariableNode); - break; - case UA_NODECLASS_METHOD: - size += sizeof(UA_MethodNode); - break; - case UA_NODECLASS_OBJECTTYPE: - size += sizeof(UA_ObjectTypeNode); - break; - case UA_NODECLASS_VARIABLETYPE: - size += sizeof(UA_VariableTypeNode); - break; - case UA_NODECLASS_REFERENCETYPE: - size += sizeof(UA_ReferenceTypeNode); - break; - case UA_NODECLASS_DATATYPE: - size += sizeof(UA_DataTypeNode); - break; - case UA_NODECLASS_VIEW: - size += sizeof(UA_ViewNode); - break; - default: - return NULL; + UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint ( + &securityPolicy->localCertificate, + &context->localCertThumbprint, true + ); + if (retval != UA_STATUSCODE_GOOD) { + EVP_PKEY_free(context->localPrivateKey); + UA_free (context); + return retval; } - NodeEntry *entry = (NodeEntry*)UA_calloc(1, size); - if(!entry) - return NULL; - UA_Node *node = (UA_Node*)&entry->nodeId; - node->nodeClass = nodeClass; - return entry; -} + + context->logger = logger; + securityPolicy->policyContext = context; + + return UA_STATUSCODE_GOOD; +} static void -deleteEntry(NodeEntry *entry) { - UA_Node_clear((UA_Node*)&entry->nodeId); - UA_free(entry); +UA_Policy_Basic128Rsa15_Clear_Context (UA_SecurityPolicy *policy) { + if (policy == NULL) { + return; + } + UA_ByteString_clear(&policy->localCertificate); + + Policy_Context_Basic128Rsa15 * ctx = (Policy_Context_Basic128Rsa15 *) policy->policyContext; + if (ctx == NULL) { + return; + } + + /* delete all allocated members in the context */ + + EVP_PKEY_free(ctx->localPrivateKey); + UA_ByteString_clear(&ctx->localCertThumbprint); + UA_free (ctx); + + return; } -static void -cleanupEntry(NodeEntry *entry) { - if(entry->deleted && entry->refCount == 0) - deleteEntry(entry); +/* create the channel context */ + +static UA_StatusCode +UA_ChannelModule_Basic128Rsa15_New_Context (const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * remoteCertificate, + void ** channelContext) { + if (securityPolicy == NULL || remoteCertificate == NULL || + channelContext == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + Channel_Context_Basic128Rsa15 * context = (Channel_Context_Basic128Rsa15 *) + UA_malloc (sizeof (Channel_Context_Basic128Rsa15)); + if (context == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + UA_ByteString_init(&context->localSymSigningKey); + UA_ByteString_init(&context->localSymEncryptingKey); + UA_ByteString_init(&context->localSymIv); + UA_ByteString_init(&context->remoteSymSigningKey); + UA_ByteString_init(&context->remoteSymEncryptingKey); + UA_ByteString_init(&context->remoteSymIv); + + UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate, + remoteCertificate); + if (retval != UA_STATUSCODE_GOOD) { + UA_free (context); + return retval; + } + + /* decode to X509 */ + context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); + if (context->remoteCertificateX509 == NULL) { + UA_ByteString_clear (&context->remoteCertificate); + UA_free (context); + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + } + + context->policyContext = (Policy_Context_Basic128Rsa15 *) + (securityPolicy->policyContext); + + *channelContext = context; + + UA_LOG_INFO (securityPolicy->logger, + UA_LOGCATEGORY_SECURITYPOLICY, + "The Basic128Rsa15 security policy channel with openssl is created."); + + return UA_STATUSCODE_GOOD; } -/***********************/ -/* Interface functions */ -/***********************/ +/* delete the channel context */ -/* Not yet inserted into the ZipContext */ -static UA_Node * -zipNsNewNode(void *nsCtx, UA_NodeClass nodeClass) { - NodeEntry *entry = newEntry(nodeClass); - if(!entry) - return NULL; - return (UA_Node*)&entry->nodeId; +static void +UA_ChannelModule_Basic128Rsa15_Delete_Context (void * channelContext) { + if (channelContext != NULL) { + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) + channelContext; + X509_free (cc->remoteCertificateX509); + UA_ByteString_clear (&cc->remoteCertificate); + UA_ByteString_clear (&cc->localSymSigningKey); + UA_ByteString_clear (&cc->localSymEncryptingKey); + UA_ByteString_clear (&cc->localSymIv); + UA_ByteString_clear (&cc->remoteSymSigningKey); + UA_ByteString_clear (&cc->remoteSymEncryptingKey); + UA_ByteString_clear (&cc->remoteSymIv); + UA_LOG_INFO (cc->policyContext->logger, + UA_LOGCATEGORY_SECURITYPOLICY, + "The Basic128Rsa15 security policy channel with openssl is deleted."); + + UA_free (cc); + } } -/* Not yet inserted into the ZipContext */ -static void -zipNsDeleteNode(void *nsCtx, UA_Node *node) { - deleteEntry(container_of(node, NodeEntry, nodeId)); +static UA_StatusCode +UA_ChannelModule_Basic128Rsa15_setLocalSymSigningKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_ByteString_clear(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); } -static const UA_Node * -zipNsGetNode(void *nsCtx, const UA_NodeId *nodeId) { - ZipContext *ns = (ZipContext*)nsCtx; - NodeEntry dummy; - dummy.nodeIdHash = UA_NodeId_hash(nodeId); - dummy.nodeId = *nodeId; - NodeEntry *entry = ZIP_FIND(NodeTree, &ns->root, &dummy); - if(!entry) - return NULL; - ++entry->refCount; - return (const UA_Node*)&entry->nodeId; +static UA_StatusCode +UA_ChannelModule_Basic128Rsa15_setLocalSymEncryptingKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_ByteString_clear(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); } -static void -zipNsReleaseNode(void *nsCtx, const UA_Node *node) { - if(!node) - return; - NodeEntry *entry = container_of(node, NodeEntry, nodeId); - UA_assert(entry->refCount > 0); - --entry->refCount; - cleanupEntry(entry); +static UA_StatusCode +UA_ChannelModule_Basic128Rsa15_setLocalSymIv (void * channelContext, + const UA_ByteString * iv) { + if (iv == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_ByteString_clear(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); } static UA_StatusCode -zipNsGetNodeCopy(void *nsCtx, const UA_NodeId *nodeId, - UA_Node **outNode) { - /* Find the node */ - const UA_Node *node = zipNsGetNode(nsCtx, nodeId); - if(!node) - return UA_STATUSCODE_BADNODEIDUNKNOWN; +UA_ChannelModule_Basic128Rsa15_setRemoteSymSigningKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - /* Create the new entry */ - NodeEntry *ne = newEntry(node->nodeClass); - if(!ne) { - zipNsReleaseNode(nsCtx, node); - return UA_STATUSCODE_BADOUTOFMEMORY; + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_ByteString_clear(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +} + +static UA_StatusCode +UA_ChannelModule_Basic128Rsa15_setRemoteSymEncryptingKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Copy the node content */ - UA_Node *nnode = (UA_Node*)&ne->nodeId; - UA_StatusCode retval = UA_Node_copy(node, nnode); - zipNsReleaseNode(nsCtx, node); - if(retval != UA_STATUSCODE_GOOD) { - deleteEntry(ne); - return retval; + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +} + +static UA_StatusCode +UA_ChannelModule_Basic128Rsa15_setRemoteSymIv (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - ne->orig = container_of(node, NodeEntry, nodeId); - *outNode = nnode; - return UA_STATUSCODE_GOOD; + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_ByteString_clear(&cc->remoteSymIv); + return UA_ByteString_copy(key, &cc->remoteSymIv); } static UA_StatusCode -zipNsInsertNode(void *nsCtx, UA_Node *node, UA_NodeId *addedNodeId) { - NodeEntry *entry = container_of(node, NodeEntry, nodeId); - ZipContext *ns = (ZipContext*)nsCtx; +UA_ChannelModule_Basic128Rsa15_compareCertificate (const void * channelContext, + const UA_ByteString * certificate) { + if(channelContext == NULL || certificate == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - /* Ensure that the NodeId is unique */ - NodeEntry dummy; - dummy.nodeId = node->nodeId; - if(node->nodeId.identifierType == UA_NODEIDTYPE_NUMERIC && - node->nodeId.identifier.numeric == 0) { - do { /* Create a random nodeid until we find an unoccupied id */ - node->nodeId.identifier.numeric = UA_UInt32_random(); - dummy.nodeId.identifier.numeric = node->nodeId.identifier.numeric; - dummy.nodeIdHash = UA_NodeId_hash(&node->nodeId); - } while(ZIP_FIND(NodeTree, &ns->root, &dummy)); - } else { - dummy.nodeIdHash = UA_NodeId_hash(&node->nodeId); - if(ZIP_FIND(NodeTree, &ns->root, &dummy)) { /* The nodeid exists */ - deleteEntry(entry); - return UA_STATUSCODE_BADNODEIDEXISTS; - } + const Channel_Context_Basic128Rsa15 * cc = + (const Channel_Context_Basic128Rsa15 *) channelContext; + return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509); +} + +static UA_StatusCode +UA_Asy_Basic128Rsa15_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * certificateThumbprint) { + if (securityPolicy == NULL || certificateThumbprint == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + Policy_Context_Basic128Rsa15 *pc = (Policy_Context_Basic128Rsa15 *) + securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) { + return UA_STATUSCODE_BADCERTIFICATEINVALID; } + return UA_STATUSCODE_GOOD; +} - /* Copy the NodeId */ - if(addedNodeId) { - UA_StatusCode retval = UA_NodeId_copy(&node->nodeId, addedNodeId); - if(retval != UA_STATUSCODE_GOOD) { - deleteEntry(entry); - return retval; - } +/* Generates a thumbprint for the specified certificate */ + +static UA_StatusCode +UA_Asy_Basic128Rsa15_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * certificate, + UA_ByteString * thumbprint) { + return UA_Openssl_X509_GetCertificateThumbprint (certificate, + thumbprint, false); +} + +static size_t +UA_AsySig_Basic128Rsa15_getRemoteSignatureSize (const void * channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Insert the node */ - entry->nodeIdHash = dummy.nodeIdHash; - ZIP_INSERT(NodeTree, &ns->root, entry, ZIP_FFS32(UA_UInt32_random())); - return UA_STATUSCODE_GOOD; + const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen; +} + +static size_t +UA_AsySig_Basic128Rsa15_getLocalSignatureSize (const void * channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + Policy_Context_Basic128Rsa15 * pc = (Policy_Context_Basic128Rsa15 *) cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + + return (size_t) keyLen; +} + +static UA_StatusCode +UA_AsySig_Basic128Rsa15_Verify (void * channelContext, + const UA_ByteString * message, + const UA_ByteString * signature) { + if (message == NULL || signature == NULL || + channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (message, + cc->remoteCertificateX509, signature); + + return retval; } static UA_StatusCode -zipNsReplaceNode(void *nsCtx, UA_Node *node) { - /* Find the node */ - const UA_Node *oldNode = zipNsGetNode(nsCtx, &node->nodeId); - if(!oldNode) { - deleteEntry(container_of(node, NodeEntry, nodeId)); - return UA_STATUSCODE_BADNODEIDUNKNOWN; +UA_AsySig_Basic128Rsa15_Sign (void * channelContext, + const UA_ByteString * message, + UA_ByteString * signature) { + if (channelContext == NULL || message == NULL || signature == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Test if the copy is current */ - NodeEntry *entry = container_of(node, NodeEntry, nodeId); - NodeEntry *oldEntry = container_of(oldNode, NodeEntry, nodeId); - if(oldEntry != entry->orig) { - /* The node was already updated since the copy was made */ - deleteEntry(entry); - zipNsReleaseNode(nsCtx, oldNode); - return UA_STATUSCODE_BADINTERNALERROR; + const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + Policy_Context_Basic128Rsa15 *pc = cc->policyContext; + return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (message, pc->localPrivateKey, signature); +} + +static size_t +UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize (const void *channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Replace */ - ZipContext *ns = (ZipContext*)nsCtx; - ZIP_REMOVE(NodeTree, &ns->root, oldEntry); - entry->nodeIdHash = oldEntry->nodeIdHash; - ZIP_INSERT(NodeTree, &ns->root, entry, ZIP_RANK(entry, zipfields)); - oldEntry->deleted = true; + const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; +} - zipNsReleaseNode(nsCtx, oldNode); - return UA_STATUSCODE_GOOD; +static size_t +UA_AsymEn_Basic128Rsa15_getRemoteBlockSize (const void *channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen; +} + +static size_t +UA_AsymEn_Basic128Rsa15_getRemoteKeyLength (const void *channelContext) { + if (channelContext == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen * 8; +} + +static size_t +UA_AsymEn_Basic128Rsa15_getLocalKeyLength (const void *channelContext) { + if (channelContext == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + const Channel_Context_Basic128Rsa15 *cc = (const Channel_Context_Basic128Rsa15 *) channelContext; + Policy_Context_Basic128Rsa15 *pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + return (size_t) keyLen * 8; +} + +static UA_StatusCode +UA_AsymEn_Basic128Rsa15_Decrypt (void * channelContext, + UA_ByteString * data) { + if (channelContext == NULL || data == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + UA_StatusCode ret = UA_Openssl_RSA_PKCS1_V15_Decrypt (data, + cc->policyContext->localPrivateKey); + return ret; } static UA_StatusCode -zipNsRemoveNode(void *nsCtx, const UA_NodeId *nodeId) { - ZipContext *ns = (ZipContext*)nsCtx; - NodeEntry dummy; - dummy.nodeIdHash = UA_NodeId_hash(nodeId); - dummy.nodeId = *nodeId; - NodeEntry *entry = ZIP_FIND(NodeTree, &ns->root, &dummy); - if(!entry) - return UA_STATUSCODE_BADNODEIDUNKNOWN; - ZIP_REMOVE(NodeTree, &ns->root, entry); - entry->deleted = true; - cleanupEntry(entry); +UA_AsymEn_Basic128Rsa15_Encrypt (void * channelContext, + UA_ByteString * data) { + if (channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + return UA_Openssl_RSA_PKCS1_V15_Encrypt (data, + UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN, + cc->remoteCertificateX509); +} + +static UA_StatusCode +UA_Sym_Basic128Rsa15_generateNonce(void *policyContext, + UA_ByteString *out) { + UA_Int32 rc = RAND_bytes(out->data, (int) out->length); + if (rc != 1) { + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } return UA_STATUSCODE_GOOD; } -struct VisitorData { - UA_NodestoreVisitor visitor; - void *visitorContext; -}; +static UA_StatusCode +UA_Sym_Basic128Rsa15_generateKey(void *policyContext, + const UA_ByteString *secret, + const UA_ByteString *seed, + UA_ByteString *out) { + return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out); +} -static void -nodeVisitor(NodeEntry *entry, void *data) { - struct VisitorData *d = (struct VisitorData*)data; - d->visitor(d->visitorContext, (UA_Node*)&entry->nodeId); +static size_t +UA_SymEn_Basic128Rsa15_getLocalKeyLength (const void *channelContext) { + /* 16 bytes 128 bits */ + return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH; } -static void -zipNsIterate(void *nsCtx, UA_NodestoreVisitor visitor, - void *visitorCtx) { - struct VisitorData d; - d.visitor = visitor; - d.visitorContext = visitorCtx; - ZipContext *ns = (ZipContext*)nsCtx; - ZIP_ITER(NodeTree, &ns->root, nodeVisitor, &d); +static size_t +UA_SymEn_Basic128Rsa15_getBlockSize (const void *channelContext) { + return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE; } -static void -deleteNodeVisitor(NodeEntry *entry, void *data) { - deleteEntry(entry); +static size_t +UA_SymEn_Basic128Rsa15_getRemoteKeyLength (const void * channelContext) { + return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH; } -/***********************/ -/* Nodestore Lifecycle */ -/***********************/ +static UA_StatusCode +UA_SymEn_Basic128Rsa15_Encrypt (void *channelContext, + UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + return UA_OpenSSL_AES_128_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data); +} -static void -zipNsClear(void *nsCtx) { - if (!nsCtx) - return; - ZipContext *ns = (ZipContext*)nsCtx; - ZIP_ITER(NodeTree, &ns->root, deleteNodeVisitor, NULL); - UA_free(ns); +static UA_StatusCode +UA_SymEn_Basic128Rsa15_Decrypt (void * channelContext, + UA_ByteString * data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + return UA_OpenSSL_AES_128_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data); } -UA_StatusCode -UA_Nodestore_ZipTree(UA_Nodestore *ns) { - /* Allocate and initialize the context */ - ZipContext *ctx = (ZipContext*)UA_malloc(sizeof(ZipContext)); - if(!ctx) - return UA_STATUSCODE_BADOUTOFMEMORY; +static size_t +UA_SymSig_Basic128Rsa15_getKeyLength (const void *channelContext) { + return UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH; +} - ZIP_INIT(&ctx->root); +static size_t +UA_SymSig_Basic128Rsa15_getSignatureSize (const void *channelContext) { + return UA_SHA1_LENGTH; +} - /* Populate the nodestore */ - ns->context = (void*)ctx; - ns->clear = zipNsClear; - ns->newNode = zipNsNewNode; - ns->deleteNode = zipNsDeleteNode; - ns->getNode = zipNsGetNode; - ns->releaseNode = zipNsReleaseNode; - ns->getNodeCopy = zipNsGetNodeCopy; - ns->insertNode = zipNsInsertNode; - ns->replaceNode = zipNsReplaceNode; - ns->removeNode = zipNsRemoveNode; - ns->iterate = zipNsIterate; +static UA_StatusCode +UA_SymSig_Basic128Rsa15_Verify (void * channelContext, + const UA_ByteString * message, + const UA_ByteString * signature) { + if (channelContext == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + return UA_OpenSSL_HMAC_SHA1_Verify (message, + &cc->remoteSymSigningKey, + signature); +} + +static UA_StatusCode +UA_SymSig_Basic128Rsa15_Sign (void * channelContext, + const UA_ByteString * message, + UA_ByteString * signature) { + if (channelContext == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; + return UA_OpenSSL_HMAC_SHA1_Sign (message, &cc->localSymSigningKey, signature); +} + +/* the main entry of Basic128Rsa15 */ + +UA_StatusCode +UA_SecurityPolicy_Basic128Rsa15 (UA_SecurityPolicy * policy, + const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey, + const UA_Logger * logger) { + + UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; + UA_StatusCode retval; + + UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The Basic128Rsa15 security policy with openssl is added."); + + UA_Openssl_Init (); + memset(policy, 0, sizeof(UA_SecurityPolicy)); + policy->logger = logger; + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15\0"); + + /* set ChannelModule context */ + + channelModule->newContext = UA_ChannelModule_Basic128Rsa15_New_Context; + channelModule->deleteContext = UA_ChannelModule_Basic128Rsa15_Delete_Context; + + channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic128Rsa15_setLocalSymSigningKey; + channelModule->setLocalSymEncryptingKey = UA_ChannelModule_Basic128Rsa15_setLocalSymEncryptingKey; + channelModule->setLocalSymIv = UA_ChannelModule_Basic128Rsa15_setLocalSymIv; + channelModule->setRemoteSymSigningKey = UA_ChannelModule_Basic128Rsa15_setRemoteSymSigningKey; + channelModule->setRemoteSymEncryptingKey = UA_ChannelModule_Basic128Rsa15_setRemoteSymEncryptingKey; + channelModule->setRemoteSymIv = UA_ChannelModule_Basic128Rsa15_setRemoteSymIv; + channelModule->compareCertificate = UA_ChannelModule_Basic128Rsa15_compareCertificate; + + retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); + + if (retval != UA_STATUSCODE_GOOD) + return retval; + + /* asymmetricModule */ + + asymmetricModule->compareCertificateThumbprint = UA_Asy_Basic128Rsa15_compareCertificateThumbprint; + asymmetricModule->makeCertificateThumbprint = UA_Asy_Basic128Rsa15_makeCertificateThumbprint; + + /* AsymmetricModule - signature algorithm */ + + UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm = + &asymmetricModule->cryptoModule.signatureAlgorithm; + asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); + asySigAlgorithm->getRemoteSignatureSize = UA_AsySig_Basic128Rsa15_getRemoteSignatureSize; + asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic128Rsa15_getLocalSignatureSize; + asySigAlgorithm->getLocalKeyLength = NULL; + asySigAlgorithm->getRemoteKeyLength = NULL; + asySigAlgorithm->verify = UA_AsySig_Basic128Rsa15_Verify; + asySigAlgorithm->sign = UA_AsySig_Basic128Rsa15_Sign; + + /* AsymmetricModule encryption algorithm */ + + UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg = + &asymmetricModule->cryptoModule.encryptionAlgorithm; + asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5\0"); + asymEncryAlg->getRemotePlainTextBlockSize = UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize; + asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic128Rsa15_getRemoteBlockSize; + asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic128Rsa15_getRemoteKeyLength; + asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic128Rsa15_getLocalKeyLength; + asymEncryAlg->decrypt = UA_AsymEn_Basic128Rsa15_Decrypt; + asymEncryAlg->encrypt = UA_AsymEn_Basic128Rsa15_Encrypt; + + /* SymmetricModule */ + + symmetricModule->secureChannelNonceLength = 16; /* 128 bits*/ + symmetricModule->generateNonce = UA_Sym_Basic128Rsa15_generateNonce; + symmetricModule->generateKey = UA_Sym_Basic128Rsa15_generateKey; + + /* Symmetric encryption Algorithm */ + + UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm = + &symmetricModule->cryptoModule.encryptionAlgorithm; + symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0"); + symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic128Rsa15_getLocalKeyLength; + symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic128Rsa15_getRemoteKeyLength; + symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize; + symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize; + symEncryptionAlgorithm->decrypt = UA_SymEn_Basic128Rsa15_Decrypt; + symEncryptionAlgorithm->encrypt = UA_SymEn_Basic128Rsa15_Encrypt; + + /* Symmetric signature Algorithm */ + + UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm = + &symmetricModule->cryptoModule.signatureAlgorithm; + symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); + symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength; + symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength; + symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize; + symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize; + + symSignatureAlgorithm->verify = UA_SymSig_Basic128Rsa15_Verify; + symSignatureAlgorithm->sign = UA_SymSig_Basic128Rsa15_Sign; + + /* set the policy context */ + + retval = UA_Policy_Basic128Rsa15_New_Context (policy, localPrivateKey, logger); + if (retval != UA_STATUSCODE_GOOD) { + UA_ByteString_clear (&policy->localCertificate); + return retval; + } + policy->clear = UA_Policy_Basic128Rsa15_Clear_Context; + + /* Use the same signature algorithm as the asymmetric component for + certificate signing (see standard) */ + policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + return UA_STATUSCODE_GOOD; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_nodestore_hashmap.c" ***********************************/ +#endif -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_basic256.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright 2014-2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2017 (c) Julian Grothoff - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2020 (c) Wind River Systems, Inc. + * Copyright 2020 (c) basysKom GmbH */ -#ifndef container_of -#define container_of(ptr, type, member) \ - (type *)((uintptr_t)ptr - offsetof(type,member)) -#endif +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) -/* The default Nodestore is simply a hash-map from NodeIds to Nodes. To find an - * entry, iterate over candidate positions according to the NodeId hash. - * - * - Tombstone or non-matching NodeId: continue searching - * - Matching NodeId: Return the entry - * - NULL: Abort the search */ -typedef struct UA_NodeMapEntry { - struct UA_NodeMapEntry *orig; /* the version this is a copy from (or NULL) */ - UA_UInt16 refCount; /* How many consumers have a reference to the node? */ - UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */ - UA_Node node; -} UA_NodeMapEntry; +#include <openssl/x509.h> +#include <openssl/rand.h> -#define UA_NODEMAP_MINSIZE 64 -#define UA_NODEMAP_TOMBSTONE ((UA_NodeMapEntry*)0x01) +#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN 42 +#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH 32 +#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH 24 +#define UA_SHA1_LENGTH 20 typedef struct { - UA_NodeMapEntry *entry; - UA_UInt32 nodeIdHash; -} UA_NodeMapSlot; + EVP_PKEY * localPrivateKey; + UA_ByteString localCertThumbprint; + const UA_Logger * logger; +} Policy_Context_Basic256; typedef struct { - UA_NodeMapSlot *slots; - UA_UInt32 size; - UA_UInt32 count; - UA_UInt32 sizePrimeIndex; -} UA_NodeMap; + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; -/*********************/ -/* HashMap Utilities */ -/*********************/ + Policy_Context_Basic256 * policyContext; + UA_ByteString remoteCertificate; + X509 * remoteCertificateX509; +} Channel_Context_Basic256; -/* The size of the hash-map is always a prime number. They are chosen to be - * close to the next power of 2. So the size ca. doubles with each prime. */ -static UA_UInt32 const primes[] = { - 7, 13, 31, 61, 127, 251, - 509, 1021, 2039, 4093, 8191, 16381, - 32749, 65521, 131071, 262139, 524287, 1048573, - 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, - 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291 -}; +static UA_StatusCode +UA_Policy_Basic256_New_Context (UA_SecurityPolicy * securityPolicy, + const UA_ByteString localPrivateKey, + const UA_Logger * logger) { + Policy_Context_Basic256 * context = (Policy_Context_Basic256 *) + UA_malloc (sizeof (Policy_Context_Basic256)); + if (context == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); -static UA_UInt32 mod(UA_UInt32 h, UA_UInt32 size) { return h % size; } -static UA_UInt32 mod2(UA_UInt32 h, UA_UInt32 size) { return 1 + (h % (size - 2)); } + if (!context->localPrivateKey) { + UA_free (context); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } -static UA_UInt16 -higher_prime_index(UA_UInt32 n) { - UA_UInt16 low = 0; - UA_UInt16 high = (UA_UInt16)(sizeof(primes) / sizeof(UA_UInt32)); - while(low != high) { - UA_UInt16 mid = (UA_UInt16)(low + ((high - low) / 2)); - if(n > primes[mid]) - low = (UA_UInt16)(mid + 1); - else - high = mid; + UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint ( + &securityPolicy->localCertificate, + &context->localCertThumbprint, true + ); + if (retval != UA_STATUSCODE_GOOD) { + EVP_PKEY_free(context->localPrivateKey); + UA_free (context); + return retval; } - return low; -} -/* Returns an empty slot or null if the nodeid exists or if no empty slot is found. */ -static UA_NodeMapSlot * -findFreeSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) { - UA_UInt32 h = UA_NodeId_hash(nodeid); - UA_UInt32 size = ns->size; - UA_UInt64 idx = mod(h, size); /* Use 64bit container to avoid overflow */ - UA_UInt32 startIdx = (UA_UInt32)idx; - UA_UInt32 hash2 = mod2(h, size); + context->logger = logger; + securityPolicy->policyContext = context; - UA_NodeMapSlot *candidate = NULL; - do { - UA_NodeMapSlot *slot = &ns->slots[(UA_UInt32)idx]; + return UA_STATUSCODE_GOOD; +} - if(slot->entry > UA_NODEMAP_TOMBSTONE) { - /* A Node with the NodeId does already exist */ - if(slot->nodeIdHash == h && - UA_NodeId_equal(&slot->entry->node.nodeId, nodeid)) - return NULL; - } else { - /* Found a candidate node */ - if(!candidate) - candidate = slot; - /* No matching node can come afterwards */ - if(slot->entry == NULL) - return candidate; - } +static void +UA_Policy_Basic256_Clear_Context (UA_SecurityPolicy *policy) { + if (policy == NULL) { + return; + } + UA_ByteString_clear(&policy->localCertificate); - idx += hash2; - if(idx >= size) - idx -= size; - } while((UA_UInt32)idx != startIdx); + Policy_Context_Basic256 * ctx = (Policy_Context_Basic256 *) policy->policyContext; + if (ctx == NULL) { + return; + } - return candidate; + /* delete all allocated members in the context */ + + EVP_PKEY_free(ctx->localPrivateKey); + UA_ByteString_clear(&ctx->localCertThumbprint); + UA_free (ctx); + + return; } -/* The occupancy of the table after the call will be about 50% */ -static UA_StatusCode -expand(UA_NodeMap *ns) { - UA_UInt32 osize = ns->size; - UA_UInt32 count = ns->count; - /* Resize only when table after removal of unused elements is either too - full or too empty */ - if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODEMAP_MINSIZE)) - return UA_STATUSCODE_GOOD; +/* create the channel context */ - UA_NodeMapSlot *oslots = ns->slots; - UA_UInt32 nindex = higher_prime_index(count * 2); - UA_UInt32 nsize = primes[nindex]; - UA_NodeMapSlot *nslots= (UA_NodeMapSlot*)UA_calloc(nsize, sizeof(UA_NodeMapSlot)); - if(!nslots) +static UA_StatusCode +UA_ChannelModule_Basic256_New_Context (const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * remoteCertificate, + void ** channelContext) { + if (securityPolicy == NULL || remoteCertificate == NULL || + channelContext == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + Channel_Context_Basic256 * context = (Channel_Context_Basic256 *) + UA_malloc (sizeof (Channel_Context_Basic256)); + if (context == NULL) { return UA_STATUSCODE_BADOUTOFMEMORY; + } - ns->slots = nslots; - ns->size = nsize; - ns->sizePrimeIndex = nindex; + UA_ByteString_init(&context->localSymSigningKey); + UA_ByteString_init(&context->localSymEncryptingKey); + UA_ByteString_init(&context->localSymIv); + UA_ByteString_init(&context->remoteSymSigningKey); + UA_ByteString_init(&context->remoteSymEncryptingKey); + UA_ByteString_init(&context->remoteSymIv); - /* recompute the position of every entry and insert the pointer */ - for(size_t i = 0, j = 0; i < osize && j < count; ++i) { - if(oslots[i].entry <= UA_NODEMAP_TOMBSTONE) - continue; - UA_NodeMapSlot *s = findFreeSlot(ns, &oslots[i].entry->node.nodeId); - UA_assert(s); - *s = oslots[i]; - ++j; + UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate, + remoteCertificate); + if (retval != UA_STATUSCODE_GOOD) { + UA_free (context); + return retval; } - UA_free(oslots); + /* decode to X509 */ + context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); + if (context->remoteCertificateX509 == NULL) { + UA_ByteString_clear (&context->remoteCertificate); + UA_free (context); + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + } + + context->policyContext = (Policy_Context_Basic256 *) + (securityPolicy->policyContext); + + *channelContext = context; + + UA_LOG_INFO (securityPolicy->logger, + UA_LOGCATEGORY_SECURITYPOLICY, + "The basic256 security policy channel with openssl is created."); + return UA_STATUSCODE_GOOD; } -static UA_NodeMapEntry * -createEntry(UA_NodeClass nodeClass) { - size_t size = sizeof(UA_NodeMapEntry) - sizeof(UA_Node); - switch(nodeClass) { - case UA_NODECLASS_OBJECT: - size += sizeof(UA_ObjectNode); - break; - case UA_NODECLASS_VARIABLE: - size += sizeof(UA_VariableNode); - break; - case UA_NODECLASS_METHOD: - size += sizeof(UA_MethodNode); - break; - case UA_NODECLASS_OBJECTTYPE: - size += sizeof(UA_ObjectTypeNode); - break; - case UA_NODECLASS_VARIABLETYPE: - size += sizeof(UA_VariableTypeNode); - break; - case UA_NODECLASS_REFERENCETYPE: - size += sizeof(UA_ReferenceTypeNode); - break; - case UA_NODECLASS_DATATYPE: - size += sizeof(UA_DataTypeNode); - break; - case UA_NODECLASS_VIEW: - size += sizeof(UA_ViewNode); - break; - default: - return NULL; +/* delete the channel context */ + +static void +UA_ChannelModule_Basic256_Delete_Context (void * channelContext) { + if (channelContext != NULL) { + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) + channelContext; + X509_free (cc->remoteCertificateX509); + UA_ByteString_clear (&cc->remoteCertificate); + UA_ByteString_clear (&cc->localSymSigningKey); + UA_ByteString_clear (&cc->localSymEncryptingKey); + UA_ByteString_clear (&cc->localSymIv); + UA_ByteString_clear (&cc->remoteSymSigningKey); + UA_ByteString_clear (&cc->remoteSymEncryptingKey); + UA_ByteString_clear (&cc->remoteSymIv); + UA_LOG_INFO (cc->policyContext->logger, + UA_LOGCATEGORY_SECURITYPOLICY, + "The basic256 security policy channel with openssl is deleted."); + + UA_free (cc); } - UA_NodeMapEntry *entry = (UA_NodeMapEntry*)UA_calloc(1, size); - if(!entry) - return NULL; - entry->node.nodeClass = nodeClass; - return entry; } -static void -deleteNodeMapEntry(UA_NodeMapEntry *entry) { - UA_Node_clear(&entry->node); - UA_free(entry); -} +/* Compares the supplied certificate with the certificate + * in the endpoint context + */ -static void -cleanupNodeMapEntry(UA_NodeMapEntry *entry) { - if(entry->deleted && entry->refCount == 0) - deleteNodeMapEntry(entry); +static UA_StatusCode +UA_Asy_Basic256_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * certificateThumbprint) { + if (securityPolicy == NULL || certificateThumbprint == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + Policy_Context_Basic256 *pc = (Policy_Context_Basic256 *) + securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) { + return UA_STATUSCODE_BADCERTIFICATEINVALID; + } + return UA_STATUSCODE_GOOD; } -static UA_NodeMapSlot * -findOccupiedSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) { - UA_UInt32 h = UA_NodeId_hash(nodeid); - UA_UInt32 size = ns->size; - UA_UInt64 idx = mod(h, size); /* Use 64bit container to avoid overflow */ - UA_UInt32 hash2 = mod2(h, size); - UA_UInt32 startIdx = (UA_UInt32)idx; +/* Generates a thumbprint for the specified certificate */ - do { - UA_NodeMapSlot *slot= &ns->slots[(UA_UInt32)idx]; - if(slot->entry > UA_NODEMAP_TOMBSTONE) { - if(slot->nodeIdHash == h && - UA_NodeId_equal(&slot->entry->node.nodeId, nodeid)) - return slot; - } else { - if(slot->entry == NULL) - return NULL; /* No further entry possible */ - } +static UA_StatusCode +UA_Asy_Basic256_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * certificate, + UA_ByteString * thumbprint) { + return UA_Openssl_X509_GetCertificateThumbprint (certificate, + thumbprint, false); +} - idx += hash2; - if(idx >= size) - idx -= size; - } while((UA_UInt32)idx != startIdx); +static UA_StatusCode +UA_ChannelModule_Basic256_setLocalSymSigningKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - return NULL; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_ByteString_clear(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); } -/***********************/ -/* Interface functions */ -/***********************/ +static UA_StatusCode +UA_ChannelModule_Basic256_setLocalSymEncryptingKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } -static UA_Node * -UA_NodeMap_newNode(void *context, UA_NodeClass nodeClass) { - UA_NodeMapEntry *entry = createEntry(nodeClass); - if(!entry) - return NULL; - return &entry->node; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_ByteString_clear(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); } -static void -UA_NodeMap_deleteNode(void *context, UA_Node *node) { - UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node); - UA_assert(&entry->node == node); - deleteNodeMapEntry(entry); -} +static UA_StatusCode +UA_ChannelModule_Basic256_setLocalSymIv (void * channelContext, + const UA_ByteString * iv) { + if (iv == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } -static const UA_Node * -UA_NodeMap_getNode(void *context, const UA_NodeId *nodeid) { - UA_NodeMap *ns = (UA_NodeMap*)context; - UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid); - if(!slot) - return NULL; - ++slot->entry->refCount; - return &slot->entry->node; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_ByteString_clear(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); } -static void -UA_NodeMap_releaseNode(void *context, const UA_Node *node) { - if (!node) - return; - UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node); - UA_assert(&entry->node == node); - UA_assert(entry->refCount > 0); - --entry->refCount; - cleanupNodeMapEntry(entry); +static UA_StatusCode +UA_ChannelModule_Basic256_setRemoteSymSigningKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_ByteString_clear(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); } static UA_StatusCode -UA_NodeMap_getNodeCopy(void *context, const UA_NodeId *nodeid, - UA_Node **outNode) { - UA_NodeMap *ns = (UA_NodeMap*)context; - UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid); - if(!slot) - return UA_STATUSCODE_BADNODEIDUNKNOWN; - UA_NodeMapEntry *entry = slot->entry; - UA_NodeMapEntry *newItem = createEntry(entry->node.nodeClass); - if(!newItem) - return UA_STATUSCODE_BADOUTOFMEMORY; - UA_StatusCode retval = UA_Node_copy(&entry->node, &newItem->node); - if(retval == UA_STATUSCODE_GOOD) { - newItem->orig = entry; /* Store the pointer to the original */ - *outNode = &newItem->node; - } else { - deleteNodeMapEntry(newItem); +UA_ChannelModule_Basic256_setRemoteSymEncryptingKey (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - return retval; + + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); } static UA_StatusCode -UA_NodeMap_removeNode(void *context, const UA_NodeId *nodeid) { - UA_NodeMap *ns = (UA_NodeMap*)context; - UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid); - if(!slot) - return UA_STATUSCODE_BADNODEIDUNKNOWN; +UA_ChannelModule_Basic256_setRemoteSymIv (void * channelContext, + const UA_ByteString * key) { + if (key == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - UA_NodeMapEntry *entry = slot->entry; - slot->entry = UA_NODEMAP_TOMBSTONE; - UA_atomic_sync(); /* Set the tombstone before cleaning up. E.g. if the - * nodestore is accessed from an interrupt. */ - entry->deleted = true; - cleanupNodeMapEntry(entry); - --ns->count; - /* Downsize the hashmap if it is very empty */ - if(ns->count * 8 < ns->size && ns->size > UA_NODEMAP_MINSIZE) - expand(ns); /* Can fail. Just continue with the bigger hashmap. */ - return UA_STATUSCODE_GOOD; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_ByteString_clear(&cc->remoteSymIv); + return UA_ByteString_copy(key, &cc->remoteSymIv); } static UA_StatusCode -UA_NodeMap_insertNode(void *context, UA_Node *node, - UA_NodeId *addedNodeId) { - UA_NodeMap *ns = (UA_NodeMap*)context; - if(ns->size * 3 <= ns->count * 4) { - if(expand(ns) != UA_STATUSCODE_GOOD) - return UA_STATUSCODE_BADINTERNALERROR; +UA_ChannelModule_Basic256_compareCertificate (const void * channelContext, + const UA_ByteString * certificate) { + if(channelContext == NULL || certificate == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - UA_NodeMapSlot *slot; - if(node->nodeId.identifierType == UA_NODEIDTYPE_NUMERIC && - node->nodeId.identifier.numeric == 0) { - /* Create a random nodeid: Start at least with 50,000 to make sure we - * don not conflict with nodes from the spec. If we find a conflict, we - * just try another identifier until we have tried all possible - * identifiers. Since the size is prime and we don't change the increase - * val, we will reach the starting id again. E.g. adding a nodeset will - * create children while there are still other nodes which need to be - * created. Thus the node ids may collide. */ - UA_UInt32 size = ns->size; - UA_UInt64 identifier = mod(50000 + size+1, UA_UINT32_MAX); /* Use 64bit to - * avoid overflow */ - UA_UInt32 increase = mod2(ns->count+1, size); - UA_UInt32 startId = (UA_UInt32)identifier; /* mod ensures us that the id - * is a valid 32 bit integer */ + const Channel_Context_Basic256 * cc = + (const Channel_Context_Basic256 *) channelContext; + return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509); +} - do { - node->nodeId.identifier.numeric = (UA_UInt32)identifier; - slot = findFreeSlot(ns, &node->nodeId); - if(slot) - break; - identifier += increase; - if(identifier >= size) - identifier -= size; - } while((UA_UInt32)identifier != startId); - } else { - slot = findFreeSlot(ns, &node->nodeId); +static size_t +UA_AsySig_Basic256_getRemoteSignatureSize (const void *channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - if(!slot) { - deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); - return UA_STATUSCODE_BADNODEIDEXISTS; + const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen; +} + +static size_t +UA_AsySig_Basic256_getLocalSignatureSize (const void *channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Copy the NodeId */ - UA_StatusCode retval = UA_STATUSCODE_GOOD; - if(addedNodeId) { - retval = UA_NodeId_copy(&node->nodeId, addedNodeId); - if(retval != UA_STATUSCODE_GOOD) { - deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); - return retval; + const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; + Policy_Context_Basic256 * pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + + return (size_t) keyLen; +} + +static UA_StatusCode +UA_AsySig_Basic256_Verify (void * channelContext, + const UA_ByteString * message, + const UA_ByteString * signature) { + if (message == NULL || signature == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - } - /* Insert the node */ - UA_NodeMapEntry *newEntry = container_of(node, UA_NodeMapEntry, node); - slot->nodeIdHash = UA_NodeId_hash(&node->nodeId); - UA_atomic_sync(); /* Set the hash first */ - slot->entry = newEntry; - ++ns->count; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (message, + cc->remoteCertificateX509, signature); return retval; } static UA_StatusCode -UA_NodeMap_replaceNode(void *context, UA_Node *node) { - UA_NodeMap *ns = (UA_NodeMap*)context; - UA_NodeMapEntry *newEntry = container_of(node, UA_NodeMapEntry, node); - - /* Find the node */ - UA_NodeMapSlot *slot = findOccupiedSlot(ns, &node->nodeId); - if(!slot) { - deleteNodeMapEntry(newEntry); - return UA_STATUSCODE_BADNODEIDUNKNOWN; +UA_AsySig_Basic256_Sign (void * channelContext, + const UA_ByteString * message, + UA_ByteString * signature) { + if (channelContext == NULL || message == NULL || signature == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* The node was already updated since the copy was made? */ - UA_NodeMapEntry *oldEntry = slot->entry; - if(oldEntry != newEntry->orig) { - deleteNodeMapEntry(newEntry); - return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + Policy_Context_Basic256 * pc = cc->policyContext; + return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (message, pc->localPrivateKey, + signature); +} + +static size_t +UA_AsymEn_Basic256_getRemotePlainTextBlockSize (const void *channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Replace the entry */ - slot->entry = newEntry; - UA_atomic_sync(); - oldEntry->deleted = true; - cleanupNodeMapEntry(oldEntry); - return UA_STATUSCODE_GOOD; + const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN; } -static void -UA_NodeMap_iterate(void *context, UA_NodestoreVisitor visitor, - void *visitorContext) { - UA_NodeMap *ns = (UA_NodeMap*)context; - for(UA_UInt32 i = 0; i < ns->size; ++i) { - UA_NodeMapSlot *slot = &ns->slots[i]; - if(slot->entry > UA_NODEMAP_TOMBSTONE) { - /* The visitor can delete the node. So refcount here. */ - slot->entry->refCount++; - visitor(visitorContext, &slot->entry->node); - slot->entry->refCount--; - cleanupNodeMapEntry(slot->entry); - } +static size_t +UA_AsymEn_Basic256_getRemoteBlockSize (const void *channelContext) { + if (channelContext == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } + + const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen; } -static void -UA_NodeMap_delete(void *context) { - UA_NodeMap *ns = (UA_NodeMap*)context; - UA_UInt32 size = ns->size; - UA_NodeMapSlot *slots = ns->slots; - for(UA_UInt32 i = 0; i < size; ++i) { - if(slots[i].entry > UA_NODEMAP_TOMBSTONE) { - /* On debugging builds, check that all nodes were release */ - UA_assert(slots[i].entry->refCount == 0); - /* Delete the node */ - deleteNodeMapEntry(slots[i].entry); - } - } - UA_free(ns->slots); - UA_free(ns); +static size_t +UA_AsymEn_Basic256_getRemoteKeyLength (const void *channelContext) { + if (channelContext == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen * 8; } -UA_StatusCode -UA_Nodestore_HashMap(UA_Nodestore *ns) { - /* Allocate and initialize the nodemap */ - UA_NodeMap *nodemap = (UA_NodeMap*)UA_malloc(sizeof(UA_NodeMap)); - if(!nodemap) - return UA_STATUSCODE_BADOUTOFMEMORY; - nodemap->sizePrimeIndex = higher_prime_index(UA_NODEMAP_MINSIZE); - nodemap->size = primes[nodemap->sizePrimeIndex]; - nodemap->count = 0; - nodemap->slots = (UA_NodeMapSlot*) - UA_calloc(nodemap->size, sizeof(UA_NodeMapSlot)); - if(!nodemap->slots) { - UA_free(nodemap); - return UA_STATUSCODE_BADOUTOFMEMORY; +static size_t +UA_AsymEn_Basic256_getLocalKeyLength (const void *channelContext) { + if (channelContext == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + const Channel_Context_Basic256 *cc = (const Channel_Context_Basic256 *) channelContext; + Policy_Context_Basic256 *pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + + return (size_t) keyLen * 8; +} + +static UA_StatusCode +UA_AsymEn_Basic256_Decrypt (void * channelContext, + UA_ByteString * data) { + if (channelContext == NULL || data == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; } - /* Populate the nodestore */ - ns->context = nodemap; - ns->clear = UA_NodeMap_delete; - ns->newNode = UA_NodeMap_newNode; - ns->deleteNode = UA_NodeMap_deleteNode; - ns->getNode = UA_NodeMap_getNode; - ns->releaseNode = UA_NodeMap_releaseNode; - ns->getNodeCopy = UA_NodeMap_getNodeCopy; - ns->insertNode = UA_NodeMap_insertNode; - ns->replaceNode = UA_NodeMap_replaceNode; - ns->removeNode = UA_NodeMap_removeNode; - ns->iterate = UA_NodeMap_iterate; - return UA_STATUSCODE_GOOD; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + UA_StatusCode ret = UA_Openssl_RSA_Oaep_Decrypt (data, + cc->policyContext->localPrivateKey); + return ret; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_config_default.c" ***********************************/ +static UA_StatusCode +UA_AsymEn_Basic256_Encrypt (void * channelContext, + UA_ByteString * data) { + if (channelContext == NULL || data == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. - * - * Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - * Copyright 2017 (c) Julian Grothoff - * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH - * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA - * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG - * Copyright 2018 (c) Fabian Arndt, Root-Core - * Copyright 2019 (c) Kalycito Infotech Private Limited - * Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green) - * Copyright 2020 (c) Wind River Systems, Inc. - */ + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + return UA_Openssl_RSA_OAEP_Encrypt (data, UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN, + cc->remoteCertificateX509); +} -#ifdef UA_ENABLE_WEBSOCKET_SERVER -#endif +static UA_StatusCode +UA_Sym_Basic256_generateNonce(void *policyContext, + UA_ByteString *out) { + UA_Int32 rc = RAND_bytes(out->data, (int) out->length); + if (rc != 1) { + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + return UA_STATUSCODE_GOOD; +} -/* Struct initialization works across ANSI C/C99/C++ if it is done when the - * variable is first declared. Assigning values to existing structs is - * heterogeneous across the three. */ -static UA_INLINE UA_UInt32Range -UA_UINT32RANGE(UA_UInt32 min, UA_UInt32 max) { - UA_UInt32Range range = {min, max}; - return range; +static UA_StatusCode +UA_Sym_Basic256_generateKey(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out); } -static UA_INLINE UA_DurationRange -UA_DURATIONRANGE(UA_Duration min, UA_Duration max) { - UA_DurationRange range = {min, max}; - return range; +static size_t +UA_SymEn_Basic256_getLocalKeyLength (const void * channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH; } -UA_Server * -UA_Server_new() { - UA_ServerConfig config; - memset(&config, 0, sizeof(UA_ServerConfig)); - /* Set a default logger and NodeStore for the initialization */ - config.logger = UA_Log_Stdout_; - UA_Nodestore_HashMap(&config.nodestore); - return UA_Server_newWithConfig(&config); +static size_t +UA_SymEn_Basic256_getBlockSize (const void * channelContext) { + return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE; } -/*******************************/ -/* Default Connection Settings */ -/*******************************/ +static size_t +UA_SymEn_Basic256_getRemoteKeyLength (const void * channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH; +} -const UA_ConnectionConfig UA_ConnectionConfig_default = { - 0, /* .protocolVersion */ - 65535, /* .sendBufferSize, 64k per chunk */ - 65535, /* .recvBufferSize, 64k per chunk */ - 0, /* .localMaxMessageSize, 0 -> unlimited */ - 0, /* .remoteMaxMessageSize, 0 -> unlimited */ - 0, /* .localMaxChunkCount, 0 -> unlimited */ - 0 /* .remoteMaxChunkCount, 0 -> unlimited */ -}; +static UA_StatusCode +UA_SymEn_Basic256_Encrypt (void * channelContext, + UA_ByteString * data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + return UA_OpenSSL_AES_256_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data); +} -/***************************/ -/* Default Server Settings */ -/***************************/ +static UA_StatusCode +UA_SymEn_Basic256_Decrypt (void * channelContext, + UA_ByteString * data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + return UA_OpenSSL_AES_256_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data); +} -#define MANUFACTURER_NAME "open62541" -#define PRODUCT_NAME "open62541 OPC UA Server" -#define PRODUCT_URI "http://open62541.org" -#define APPLICATION_NAME "open62541-based OPC UA Application" -#define APPLICATION_URI "urn:unconfigured:application" -#define APPLICATION_URI_SERVER "urn:open62541.server.application" +static size_t +UA_SymSig_Basic256_getKeyLength (const void * channelContext) { + return UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH; +} -#define STRINGIFY(arg) #arg -#define VERSION(MAJOR, MINOR, PATCH, LABEL) \ - STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL +static size_t +UA_SymSig_Basic256_getSignatureSize (const void * channelContext) { + return UA_SHA1_LENGTH; +} static UA_StatusCode -createEndpoint(UA_ServerConfig *conf, UA_EndpointDescription *endpoint, - const UA_SecurityPolicy *securityPolicy, - UA_MessageSecurityMode securityMode) { - UA_EndpointDescription_init(endpoint); +UA_SymSig_Basic256_Verify (void * channelContext, + const UA_ByteString * message, + const UA_ByteString * signature) { + if (channelContext == NULL || + message == NULL || signature == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + return UA_OpenSSL_HMAC_SHA1_Verify (message, + &cc->remoteSymSigningKey, + signature); +} - endpoint->securityMode = securityMode; - UA_String_copy(&securityPolicy->policyUri, &endpoint->securityPolicyUri); - endpoint->transportProfileUri = - UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"); +static UA_StatusCode +UA_SymSig_Basic256_Sign (void * channelContext, + const UA_ByteString * message, + UA_ByteString * signature) { + if (channelContext == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; + return UA_OpenSSL_HMAC_SHA1_Sign (message, &cc->localSymSigningKey, signature); +} - /* Add security level value for the corresponding message security mode */ - endpoint->securityLevel = (UA_Byte) securityMode; +/* the main entry of Basic256 */ - /* Enable all login mechanisms from the access control plugin */ - UA_StatusCode retval = UA_Array_copy(conf->accessControl.userTokenPolicies, - conf->accessControl.userTokenPoliciesSize, - (void **)&endpoint->userIdentityTokens, - &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); - if(retval != UA_STATUSCODE_GOOD) - return retval; - endpoint->userIdentityTokensSize = conf->accessControl.userTokenPoliciesSize; +UA_StatusCode +UA_SecurityPolicy_Basic256 (UA_SecurityPolicy * policy, + const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey, + const UA_Logger * logger) { + UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; + UA_StatusCode retval; - UA_String_copy(&securityPolicy->localCertificate, &endpoint->serverCertificate); - UA_ApplicationDescription_copy(&conf->applicationDescription, &endpoint->server); + UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The basic256 security policy with openssl is added."); - return UA_STATUSCODE_GOOD; -} + UA_Openssl_Init (); + memset(policy, 0, sizeof(UA_SecurityPolicy)); + policy->logger = logger; + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256\0"); -static const size_t usernamePasswordsSize = 2; -static UA_UsernamePasswordLogin usernamePasswords[2] = { - {UA_STRING_STATIC("user1"), UA_STRING_STATIC("password")}, - {UA_STRING_STATIC("user2"), UA_STRING_STATIC("password1")}}; + /* set ChannelModule context */ -static UA_StatusCode -setDefaultConfig(UA_ServerConfig *conf) { - if (!conf) - return UA_STATUSCODE_BADINVALIDARGUMENT; + channelModule->newContext = UA_ChannelModule_Basic256_New_Context; + channelModule->deleteContext = UA_ChannelModule_Basic256_Delete_Context; - if(conf->nodestore.context == NULL) - UA_Nodestore_HashMap(&conf->nodestore); + channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic256_setLocalSymSigningKey; + channelModule->setLocalSymEncryptingKey = UA_ChannelModule_Basic256_setLocalSymEncryptingKey; + channelModule->setLocalSymIv = UA_ChannelModule_Basic256_setLocalSymIv; + channelModule->setRemoteSymSigningKey = UA_ChannelModule_Basic256_setRemoteSymSigningKey; + channelModule->setRemoteSymEncryptingKey = UA_ChannelModule_Basic256_setRemoteSymEncryptingKey; + channelModule->setRemoteSymIv = UA_ChannelModule_Basic256_setRemoteSymIv; + channelModule->compareCertificate = UA_ChannelModule_Basic256_compareCertificate; - /* --> Start setting the default static config <-- */ - conf->nThreads = 1; + retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); - /* Allow user to set his own logger */ - if (!conf->logger.log) - conf->logger = UA_Log_Stdout_; + if (retval != UA_STATUSCODE_GOOD) + return retval; - conf->shutdownDelay = 0.0; + /* asymmetricModule */ - /* Server Description */ - UA_BuildInfo_clear(&conf->buildInfo); - conf->buildInfo.productUri = UA_STRING_ALLOC(PRODUCT_URI); - conf->buildInfo.manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME); - conf->buildInfo.productName = UA_STRING_ALLOC(PRODUCT_NAME); - conf->buildInfo.softwareVersion = - UA_STRING_ALLOC(VERSION(UA_OPEN62541_VER_MAJOR, UA_OPEN62541_VER_MINOR, - UA_OPEN62541_VER_PATCH, UA_OPEN62541_VER_LABEL)); - #ifdef UA_PACK_DEBIAN - conf->buildInfo.buildNumber = UA_STRING_ALLOC("deb"); - #else - conf->buildInfo.buildNumber = UA_STRING_ALLOC(__DATE__ " " __TIME__); - #endif - conf->buildInfo.buildDate = UA_DateTime_now(); + asymmetricModule->compareCertificateThumbprint = UA_Asy_Basic256_compareCertificateThumbprint; + asymmetricModule->makeCertificateThumbprint = UA_Asy_Basic256_makeCertificateThumbprint; - UA_ApplicationDescription_clear(&conf->applicationDescription); - conf->applicationDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI_SERVER); - conf->applicationDescription.productUri = UA_STRING_ALLOC(PRODUCT_URI); - conf->applicationDescription.applicationName = - UA_LOCALIZEDTEXT_ALLOC("en", APPLICATION_NAME); - conf->applicationDescription.applicationType = UA_APPLICATIONTYPE_SERVER; - /* conf->applicationDescription.gatewayServerUri = UA_STRING_NULL; */ - /* conf->applicationDescription.discoveryProfileUri = UA_STRING_NULL; */ - /* conf->applicationDescription.discoveryUrlsSize = 0; */ - /* conf->applicationDescription.discoveryUrls = NULL; */ + /* AsymmetricModule - signature algorithm */ -#ifdef UA_ENABLE_DISCOVERY_MULTICAST - UA_MdnsDiscoveryConfiguration_clear(&conf->discovery.mdns); - conf->discovery.mdnsInterfaceIP = UA_STRING_NULL; -# if !defined(UA_HAS_GETIFADDR) - conf->discovery.ipAddressList = NULL; - conf->discovery.ipAddressListSize = 0; -# endif -#endif + UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm = + &asymmetricModule->cryptoModule.signatureAlgorithm; + asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); + asySigAlgorithm->getRemoteSignatureSize = UA_AsySig_Basic256_getRemoteSignatureSize; + asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic256_getLocalSignatureSize; + asySigAlgorithm->verify = UA_AsySig_Basic256_Verify; + asySigAlgorithm->sign = UA_AsySig_Basic256_Sign; + asySigAlgorithm->getLocalKeyLength = NULL; + asySigAlgorithm->getRemoteKeyLength = NULL; - /* Custom DataTypes */ - /* conf->customDataTypesSize = 0; */ - /* conf->customDataTypes = NULL; */ + /* AsymmetricModule encryption algorithm */ - /* Networking */ - /* conf->networkLayersSize = 0; */ - /* conf->networkLayers = NULL; */ - /* conf->customHostname = UA_STRING_NULL; */ + UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg = + &asymmetricModule->cryptoModule.encryptionAlgorithm; + asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); + asymEncryAlg->getRemotePlainTextBlockSize = UA_AsymEn_Basic256_getRemotePlainTextBlockSize; + asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic256_getRemoteBlockSize; + asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic256_getRemoteKeyLength; + asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic256_getLocalKeyLength; + asymEncryAlg->decrypt = UA_AsymEn_Basic256_Decrypt; + asymEncryAlg->encrypt = UA_AsymEn_Basic256_Encrypt; - /* Endpoints */ - /* conf->endpoints = {0, NULL}; */ + /* SymmetricModule */ - /* Certificate Verification that accepts every certificate. Can be - * overwritten when the policy is specialized. */ - UA_CertificateVerification_AcceptAll(&conf->certificateVerification); + symmetricModule->secureChannelNonceLength = 32; + symmetricModule->generateNonce = UA_Sym_Basic256_generateNonce; + symmetricModule->generateKey = UA_Sym_Basic256_generateKey; - /* * Global Node Lifecycle * */ - /* conf->nodeLifecycle.constructor = NULL; */ - /* conf->nodeLifecycle.destructor = NULL; */ - /* conf->nodeLifecycle.createOptionalChild = NULL; */ - /* conf->nodeLifecycle.generateChildNodeId = NULL; */ + /* Symmetric encryption Algorithm */ - /* Relax constraints for the InformationModel */ - conf->relaxEmptyValueConstraint = true; /* Allow empty values */ + UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm = + &symmetricModule->cryptoModule.encryptionAlgorithm; + symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0"); + symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic256_getLocalKeyLength; + symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic256_getRemoteKeyLength; + symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic256_getBlockSize; + symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic256_getBlockSize; + symEncryptionAlgorithm->decrypt = UA_SymEn_Basic256_Decrypt; + symEncryptionAlgorithm->encrypt = UA_SymEn_Basic256_Encrypt; - /* Limits for SecureChannels */ - conf->maxSecureChannels = 40; - conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */ + /* Symmetric signature Algorithm */ - /* Limits for Sessions */ - conf->maxSessions = 100; - conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */ + UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm = + &symmetricModule->cryptoModule.signatureAlgorithm; + symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); + symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic256_getKeyLength; + symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic256_getKeyLength; + symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Basic256_getSignatureSize; + symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic256_getSignatureSize; + symSignatureAlgorithm->verify = UA_SymSig_Basic256_Verify; + symSignatureAlgorithm->sign = UA_SymSig_Basic256_Sign; - /* Limits for Subscriptions */ - conf->publishingIntervalLimits = UA_DURATIONRANGE(100.0, 3600.0 * 1000.0); - conf->lifeTimeCountLimits = UA_UINT32RANGE(3, 15000); - conf->keepAliveCountLimits = UA_UINT32RANGE(1, 100); - conf->maxNotificationsPerPublish = 1000; - conf->enableRetransmissionQueue = true; - conf->maxRetransmissionQueueSize = 0; /* unlimited */ -#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS - conf->maxEventsPerNode = 0; /* unlimited */ -#endif + /* set the policy context */ - /* Limits for MonitoredItems */ - conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0); - conf->queueSizeLimits = UA_UINT32RANGE(1, 100); + retval = UA_Policy_Basic256_New_Context (policy, localPrivateKey, logger); + if (retval != UA_STATUSCODE_GOOD) { + UA_ByteString_clear (&policy->localCertificate); + return retval; + } + policy->clear = UA_Policy_Basic256_Clear_Context; + + /* Use the same signature algorithm as the asymmetric component for + certificate signing (see standard) */ + policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + + return UA_STATUSCODE_GOOD; +} -#ifdef UA_ENABLE_DISCOVERY - conf->discovery.cleanupTimeout = 60 * 60; #endif -#ifdef UA_ENABLE_HISTORIZING - /* conf->accessHistoryDataCapability = UA_FALSE; */ - /* conf->maxReturnDataValues = 0; */ +/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_basic256sha256.c" ****/ - /* conf->accessHistoryEventsCapability = UA_FALSE; */ - /* conf->maxReturnEventValues = 0; */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Wind River Systems, Inc. + * Copyright 2020 (c) basysKom GmbH + */ - /* conf->insertDataCapability = UA_FALSE; */ - /* conf->insertEventCapability = UA_FALSE; */ - /* conf->insertAnnotationsCapability = UA_FALSE; */ - /* conf->replaceDataCapability = UA_FALSE; */ - /* conf->replaceEventCapability = UA_FALSE; */ +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) - /* conf->updateDataCapability = UA_FALSE; */ - /* conf->updateEventCapability = UA_FALSE; */ - /* conf->deleteRawCapability = UA_FALSE; */ - /* conf->deleteEventCapability = UA_FALSE; */ - /* conf->deleteAtTimeDataCapability = UA_FALSE; */ -#endif +#include <openssl/hmac.h> +#include <openssl/sha.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> +#include <openssl/rand.h> +#include <openssl/rsa.h> -#if UA_MULTITHREADING >= 100 - conf->maxAsyncOperationQueueSize = 0; - conf->asyncOperationTimeout = 120000; /* Async Operation Timeout in ms (2 minutes) */ -#endif +#define UA_SHA256_LENGTH 32 /* 256 bit */ +#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42 +#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32 +#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH 32 +#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256 +#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512 - /* --> Finish setting the default static config <-- */ +typedef struct { + EVP_PKEY *localPrivateKey; + UA_ByteString localCertThumbprint; + const UA_Logger *logger; +} Policy_Context_Basic256Sha256; - return UA_STATUSCODE_GOOD; -} +typedef struct { + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; -UA_EXPORT UA_StatusCode -UA_ServerConfig_setBasics(UA_ServerConfig* conf) { - UA_StatusCode res = setDefaultConfig(conf); - UA_LOG_WARNING(&conf->logger, UA_LOGCATEGORY_USERLAND, - "AcceptAll Certificate Verification. " - "Any remote certificate will be accepted."); - return res; -} + Policy_Context_Basic256Sha256 *policyContext; + UA_ByteString remoteCertificate; + X509 *remoteCertificateX509; /* X509 */ +} Channel_Context_Basic256Sha256; -static UA_StatusCode -addDefaultNetworkLayers(UA_ServerConfig *conf, UA_UInt16 portNumber, - UA_UInt32 sendBufferSize, UA_UInt32 recvBufferSize) { - return UA_ServerConfig_addNetworkLayerTCP(conf, portNumber, sendBufferSize, recvBufferSize); -} +/* create the policy context */ -#ifdef UA_ENABLE_WEBSOCKET_SERVER -UA_EXPORT UA_StatusCode -UA_ServerConfig_addNetworkLayerWS(UA_ServerConfig *conf, UA_UInt16 portNumber, - UA_UInt32 sendBufferSize, UA_UInt32 recvBufferSize) { - /* Add a network layer */ - UA_ServerNetworkLayer *tmp = (UA_ServerNetworkLayer *) - UA_realloc(conf->networkLayers, - sizeof(UA_ServerNetworkLayer) * (1 + conf->networkLayersSize)); - if(!tmp) +static UA_StatusCode +UA_Policy_New_Context(UA_SecurityPolicy * securityPolicy, + const UA_ByteString localPrivateKey, + const UA_Logger *logger) { + Policy_Context_Basic256Sha256 *context = (Policy_Context_Basic256Sha256 *) + UA_malloc(sizeof(Policy_Context_Basic256Sha256)); + if(context == NULL) return UA_STATUSCODE_BADOUTOFMEMORY; - conf->networkLayers = tmp; + context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); - UA_ConnectionConfig config = UA_ConnectionConfig_default; - if (sendBufferSize > 0) - config.sendBufferSize = sendBufferSize; - if (recvBufferSize > 0) - config.recvBufferSize = recvBufferSize; + if(!context->localPrivateKey) { + UA_free(context); + return UA_STATUSCODE_BADINVALIDARGUMENT; + } - conf->networkLayers[conf->networkLayersSize] = - UA_ServerNetworkLayerWS(config, portNumber, &conf->logger); - if (!conf->networkLayers[conf->networkLayersSize].handle) - return UA_STATUSCODE_BADOUTOFMEMORY; - conf->networkLayersSize++; + UA_StatusCode retval = + UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate, + &context->localCertThumbprint, true); + if(retval != UA_STATUSCODE_GOOD) { + EVP_PKEY_free(context->localPrivateKey); + UA_free(context); + return retval; + } + context->logger = logger; + securityPolicy->policyContext = context; return UA_STATUSCODE_GOOD; } -#endif -UA_EXPORT UA_StatusCode -UA_ServerConfig_addNetworkLayerTCP(UA_ServerConfig *conf, UA_UInt16 portNumber, - UA_UInt32 sendBufferSize, UA_UInt32 recvBufferSize) { - /* Add a network layer */ - UA_ServerNetworkLayer *tmp = (UA_ServerNetworkLayer *) - UA_realloc(conf->networkLayers, - sizeof(UA_ServerNetworkLayer) * (1 + conf->networkLayersSize)); - if(!tmp) - return UA_STATUSCODE_BADOUTOFMEMORY; - conf->networkLayers = tmp; - - UA_ConnectionConfig config = UA_ConnectionConfig_default; - if (sendBufferSize > 0) - config.sendBufferSize = sendBufferSize; - if (recvBufferSize > 0) - config.recvBufferSize = recvBufferSize; +/* Clear the policy context */ +static void +UA_Policy_Clear_Context(UA_SecurityPolicy *policy) { + if(policy == NULL) + return; - conf->networkLayers[conf->networkLayersSize] = - UA_ServerNetworkLayerTCP(config, portNumber, 0, &conf->logger); - if (!conf->networkLayers[conf->networkLayersSize].handle) - return UA_STATUSCODE_BADOUTOFMEMORY; - conf->networkLayersSize++; + UA_ByteString_clear(&policy->localCertificate); - return UA_STATUSCODE_GOOD; + /* Delete all allocated members in the context */ + Policy_Context_Basic256Sha256 *pc = + (Policy_Context_Basic256Sha256 *) policy->policyContext; + EVP_PKEY_free(pc->localPrivateKey); + UA_ByteString_clear(&pc->localCertThumbprint); + UA_free(pc); + return; } -UA_EXPORT UA_StatusCode -UA_ServerConfig_addSecurityPolicyNone(UA_ServerConfig *config, - const UA_ByteString *certificate) { - /* Allocate the SecurityPolicies */ - UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) - UA_realloc(config->securityPolicies, - sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); - if(!tmp) +/* create the channel context */ + +static UA_StatusCode +UA_ChannelModule_New_Context(const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * remoteCertificate, + void ** channelContext) { + if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Channel_Context_Basic256Sha256 *context = (Channel_Context_Basic256Sha256 *) + UA_malloc(sizeof(Channel_Context_Basic256Sha256)); + if(context == NULL) return UA_STATUSCODE_BADOUTOFMEMORY; - config->securityPolicies = tmp; - - /* Populate the SecurityPolicies */ - UA_ByteString localCertificate = UA_BYTESTRING_NULL; - if(certificate) - localCertificate = *certificate; + + UA_ByteString_init(&context->localSymSigningKey); + UA_ByteString_init(&context->localSymEncryptingKey); + UA_ByteString_init(&context->localSymIv); + UA_ByteString_init(&context->remoteSymSigningKey); + UA_ByteString_init(&context->remoteSymEncryptingKey); + UA_ByteString_init(&context->remoteSymIv); + UA_StatusCode retval = - UA_SecurityPolicy_None(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, &config->logger); + UA_copyCertificate(&context->remoteCertificate, remoteCertificate); if(retval != UA_STATUSCODE_GOOD) { - if(config->securityPoliciesSize == 0) { - UA_free(config->securityPolicies); - config->securityPolicies = NULL; - } + UA_free(context); return retval; } - config->securityPoliciesSize++; - return UA_STATUSCODE_GOOD; -} - -UA_EXPORT UA_StatusCode -UA_ServerConfig_addEndpoint(UA_ServerConfig *config, const UA_String securityPolicyUri, - UA_MessageSecurityMode securityMode) { - /* Allocate the endpoint */ - UA_EndpointDescription *tmp = (UA_EndpointDescription *) - UA_realloc(config->endpoints, - sizeof(UA_EndpointDescription) * (1 + config->endpointsSize)); - if(!tmp) { - return UA_STATUSCODE_BADOUTOFMEMORY; + /* decode to X509 */ + context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); + if(context->remoteCertificateX509 == NULL) { + UA_ByteString_clear(&context->remoteCertificate); + UA_free(context); } - config->endpoints = tmp; - /* Lookup the security policy */ - const UA_SecurityPolicy *policy = NULL; - for (size_t i = 0; i < config->securityPoliciesSize; ++i) { - if (UA_String_equal(&securityPolicyUri, &config->securityPolicies[i].policyUri)) { - policy = &config->securityPolicies[i]; - break; - } - } - if (!policy) - return UA_STATUSCODE_BADINVALIDARGUMENT; + context->policyContext = + (Policy_Context_Basic256Sha256 *)securityPolicy->policyContext; + *channelContext = context; - /* Populate the endpoint */ - UA_StatusCode retval = - createEndpoint(config, &config->endpoints[config->endpointsSize], - policy, securityMode); - if(retval != UA_STATUSCODE_GOOD) - return retval; - config->endpointsSize++; + UA_LOG_INFO(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The basic256sha256 security policy channel with openssl is created."); return UA_STATUSCODE_GOOD; } -UA_EXPORT UA_StatusCode -UA_ServerConfig_addAllEndpoints(UA_ServerConfig *config) { - /* Allocate the endpoints */ - UA_EndpointDescription * tmp = (UA_EndpointDescription *) - UA_realloc(config->endpoints, - sizeof(UA_EndpointDescription) * - (2 * config->securityPoliciesSize + config->endpointsSize)); - if(!tmp) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } - config->endpoints = tmp; +/* delete the channel context */ - /* Populate the endpoints */ - for(size_t i = 0; i < config->securityPoliciesSize; ++i) { - if(UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &config->securityPolicies[i].policyUri)) { - UA_StatusCode retval = - createEndpoint(config, &config->endpoints[config->endpointsSize], - &config->securityPolicies[i], UA_MESSAGESECURITYMODE_NONE); - if(retval != UA_STATUSCODE_GOOD) - return retval; - config->endpointsSize++; - } else { - UA_StatusCode retval = - createEndpoint(config, &config->endpoints[config->endpointsSize], - &config->securityPolicies[i], UA_MESSAGESECURITYMODE_SIGN); - if(retval != UA_STATUSCODE_GOOD) - return retval; - config->endpointsSize++; +static void +UA_ChannelModule_Delete_Context(void * channelContext) { + if(!channelContext) + return; + + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *)channelContext; + X509_free(cc->remoteCertificateX509); + UA_ByteString_clear(&cc->remoteCertificate); + UA_ByteString_clear(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymIv); + UA_ByteString_clear(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymIv); + + UA_LOG_INFO(cc->policyContext->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The basic256sha256 security policy channel with openssl is deleted."); + UA_free(cc); +} - retval = createEndpoint(config, &config->endpoints[config->endpointsSize], - &config->securityPolicies[i], - UA_MESSAGESECURITYMODE_SIGNANDENCRYPT); - if(retval != UA_STATUSCODE_GOOD) - return retval; - config->endpointsSize++; - } - } +/* Verifies the signature of the message using the provided keys in the context. + * AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ +static UA_StatusCode +UA_AsySig_Basic256Sha256_Verify(void *channelContext, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(message == NULL || signature == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = + (Channel_Context_Basic256Sha256 *) channelContext; + return UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(message, cc->remoteCertificateX509, + signature); +} + +/* Compares the supplied certificate with the certificate + * in the endpoint context + */ + +static UA_StatusCode +UA_compareCertificateThumbprint(const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * certificateThumbprint) { + if(securityPolicy == NULL || certificateThumbprint == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + Policy_Context_Basic256Sha256 *pc = (Policy_Context_Basic256Sha256 *) + securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) + return UA_STATUSCODE_BADCERTIFICATEINVALID; return UA_STATUSCODE_GOOD; } -UA_EXPORT UA_StatusCode -UA_ServerConfig_setMinimalCustomBuffer(UA_ServerConfig *config, UA_UInt16 portNumber, - const UA_ByteString *certificate, - UA_UInt32 sendBufferSize, - UA_UInt32 recvBufferSize) { - if(!config) +/* Generates a thumbprint for the specified certificate */ + +static UA_StatusCode +UA_makeCertificateThumbprint(const UA_SecurityPolicy * securityPolicy, + const UA_ByteString * certificate, + UA_ByteString * thumbprint) { + return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false); +} + +static UA_StatusCode +UA_Asym_Basic256Sha256_Decrypt(void * channelContext, UA_ByteString * data) { + if(channelContext == NULL || data == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; - UA_StatusCode retval = setDefaultConfig(config); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(config); - return retval; - } + Channel_Context_Basic256Sha256 * cc = + (Channel_Context_Basic256Sha256 *) channelContext; + return UA_Openssl_RSA_Oaep_Decrypt(data, cc->policyContext->localPrivateKey); +} - retval = addDefaultNetworkLayers(config, portNumber, sendBufferSize, recvBufferSize); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(config); - return retval; - } +static size_t +UA_Asym_Basic256Sha256_getRemoteSignatureSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - /* Allocate the SecurityPolicies */ - retval = UA_ServerConfig_addSecurityPolicyNone(config, certificate); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(config); - return retval; - } + const Channel_Context_Basic256Sha256 * cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen; +} - /* Initialize the Access Control plugin */ - retval = UA_AccessControl_default(config, true, - &config->securityPolicies[config->securityPoliciesSize-1].policyUri, - usernamePasswordsSize, usernamePasswords); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(config); - return retval; - } +static size_t +UA_AsySig_Basic256Sha256_getLocalSignatureSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - /* Allocate the endpoint */ - retval = UA_ServerConfig_addEndpoint(config, UA_SECURITY_POLICY_NONE_URI, - UA_MESSAGESECURITYMODE_NONE); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(config); - return retval; - } + const Channel_Context_Basic256Sha256 *cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + Policy_Context_Basic256Sha256 * pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen); + return (size_t) keyLen; +} - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "AcceptAll Certificate Verification. " - "Any remote certificate will be accepted."); +static size_t +UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - return UA_STATUSCODE_GOOD; + const Channel_Context_Basic256Sha256 *cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN; } -#ifdef UA_ENABLE_ENCRYPTION +static size_t +UA_AsymEn_Basic256Sha256_getRemoteBlockSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -UA_EXPORT UA_StatusCode -UA_ServerConfig_addSecurityPolicyBasic128Rsa15(UA_ServerConfig *config, - const UA_ByteString *certificate, - const UA_ByteString *privateKey) { - /* Allocate the SecurityPolicies */ - UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) - UA_realloc(config->securityPolicies, - sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); - if(!tmp) - return UA_STATUSCODE_BADOUTOFMEMORY; - config->securityPolicies = tmp; - - /* Populate the SecurityPolicies */ - UA_ByteString localCertificate = UA_BYTESTRING_NULL; - UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; - if(certificate) - localCertificate = *certificate; - if(privateKey) - localPrivateKey = *privateKey; - UA_StatusCode retval = - UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, localPrivateKey, &config->logger); - if(retval != UA_STATUSCODE_GOOD) { - if(config->securityPoliciesSize == 0) { - UA_free(config->securityPolicies); - config->securityPolicies = NULL; - } - return retval; - } + const Channel_Context_Basic256Sha256 * cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen; +} - config->securityPoliciesSize++; - return UA_STATUSCODE_GOOD; +static size_t +UA_AsymEn_Basic256Sha256_getRemoteKeyLength(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Basic256Sha256 *cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t) keyLen * 8; } -UA_EXPORT UA_StatusCode -UA_ServerConfig_addSecurityPolicyBasic256(UA_ServerConfig *config, - const UA_ByteString *certificate, - const UA_ByteString *privateKey) { - /* Allocate the SecurityPolicies */ - UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) - UA_realloc(config->securityPolicies, - sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); - if(!tmp) - return UA_STATUSCODE_BADOUTOFMEMORY; - config->securityPolicies = tmp; +static UA_StatusCode +UA_Sym_Basic256Sha256_generateNonce(void *policyContext, + UA_ByteString *out) { + UA_Int32 rc = RAND_bytes(out->data, (int) out->length); + if(rc != 1) + return UA_STATUSCODE_BADUNEXPECTEDERROR; + return UA_STATUSCODE_GOOD; +} + +static size_t +UA_SymEn_Basic256Sha256_getLocalKeyLength(const void *channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH; +} + +static size_t +UA_SymSig_Basic256Sha256_getLocalKeyLength(const void *channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH; +} + +static UA_StatusCode +UA_Sym_Basic256Sha256_generateKey(void *policyContext, + const UA_ByteString *secret, + const UA_ByteString *seed, + UA_ByteString *out) { + return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out); +} + +static UA_StatusCode +UA_ChannelModule_Basic256Sha256_setLocalSymSigningKey(void * channelContext, + const UA_ByteString * key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + UA_ByteString_clear(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); +} + +static UA_StatusCode +UA_ChannelM_Basic256Sha256_setLocalSymEncryptingKey(void * channelContext, + const UA_ByteString * key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + UA_ByteString_clear(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); +} + +static UA_StatusCode +UA_ChannelM_Basic256Sha256_setLocalSymIv(void * channelContext, + const UA_ByteString * iv) { + if(iv == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + UA_ByteString_clear(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); +} + +static size_t +UA_SymEn_Basic256Sha256_getRemoteKeyLength(const void * channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH; +} + +static size_t +UA_SymEn_Basic256Sha256_getBlockSize(const void *channelContext) { + return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE; +} + +static size_t +UA_SymSig_Basic256Sha256_getRemoteKeyLength(const void * channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH; +} + +static UA_StatusCode +UA_ChannelM_Basic256Sha256_setRemoteSymSigningKey(void *channelContext, + const UA_ByteString * key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + UA_ByteString_clear(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +} + +static UA_StatusCode +UA_ChannelM_Basic256Sha256_setRemoteSymEncryptingKey(void *channelContext, + const UA_ByteString * key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +} + +static UA_StatusCode +UA_ChannelM_Basic256Sha256_setRemoteSymIv(void *channelContext, + const UA_ByteString * key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + UA_ByteString_clear(&cc->remoteSymIv); + return UA_ByteString_copy(key, &cc->remoteSymIv); +} + +static UA_StatusCode +UA_AsySig_Basic256Sha256_sign(void *channelContext, const UA_ByteString * message, + UA_ByteString *signature) { + if(channelContext == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 *cc = (Channel_Context_Basic256Sha256 *) channelContext; + Policy_Context_Basic256Sha256 *pc = cc->policyContext; + return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature); +} + +static UA_StatusCode +UA_AsymEn_Basic256Sha256_encrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = + (Channel_Context_Basic256Sha256 *) channelContext; + return UA_Openssl_RSA_OAEP_Encrypt(data, UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN, + cc->remoteCertificateX509); +} + +static size_t +UA_SymSig_Basic256Sha256_getRemoteSignatureSize(const void *channelContext) { + return UA_SHA256_LENGTH; +} + +static UA_StatusCode +UA_SymSig_Basic256Sha256_verify(void *channelContext, const UA_ByteString *message, + const UA_ByteString *signature) { + if(channelContext == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - /* Populate the SecurityPolicies */ - UA_ByteString localCertificate = UA_BYTESTRING_NULL; - UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; - if(certificate) - localCertificate = *certificate; - if(privateKey) - localPrivateKey = *privateKey; - UA_StatusCode retval = - UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, localPrivateKey, &config->logger); - if(retval != UA_STATUSCODE_GOOD) { - if(config->securityPoliciesSize == 0) { - UA_free(config->securityPolicies); - config->securityPolicies = NULL; - } - return retval; - } + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature); +} - config->securityPoliciesSize++; - return UA_STATUSCODE_GOOD; +static UA_StatusCode +UA_SymSig_Basic256Sha256_sign(void *channelContext, const UA_ByteString *message, + UA_ByteString *signature) { + if(channelContext == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature); } -UA_EXPORT UA_StatusCode -UA_ServerConfig_addSecurityPolicyBasic256Sha256(UA_ServerConfig *config, - const UA_ByteString *certificate, - const UA_ByteString *privateKey) { - /* Allocate the SecurityPolicies */ - UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) - UA_realloc(config->securityPolicies, - sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); - if(!tmp) - return UA_STATUSCODE_BADOUTOFMEMORY; - config->securityPolicies = tmp; +static size_t +UA_SymSig_Basic256Sha256_getLocalSignatureSize(const void * channelContext) { + return UA_SHA256_LENGTH; +} + +static UA_StatusCode +UA_SymEn_Basic256Sha256_decrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv, + &cc->remoteSymEncryptingKey, data); +} + +static UA_StatusCode +UA_SymEn_Basic256Sha256_encrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - /* Populate the SecurityPolicies */ - UA_ByteString localCertificate = UA_BYTESTRING_NULL; - UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; - if(certificate) - localCertificate = *certificate; - if(privateKey) - localPrivateKey = *privateKey; + Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; + return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey, data); +} + +static UA_StatusCode +UA_ChannelM_Basic256Sha256_compareCertificate(const void *channelContext, + const UA_ByteString *certificate) { + if(channelContext == NULL || certificate == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Basic256Sha256 * cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509); +} + +static size_t +UA_AsymEn_Basic256Sha256_getLocalKeyLength(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Basic256Sha256 * cc = + (const Channel_Context_Basic256Sha256 *) channelContext; + Policy_Context_Basic256Sha256 *pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen); + return (size_t) keyLen * 8; +} + +/* the main entry of Basic256Sha256 */ + +UA_StatusCode +UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, + const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey, + const UA_Logger *logger) { + UA_SecurityPolicyAsymmetricModule *asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule *symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule *channelModule = &policy->channelModule; + UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The basic256sha256 security policy with openssl is added."); + + UA_Openssl_Init(); + memset(policy, 0, sizeof(UA_SecurityPolicy)); + policy->logger = logger; + policy->policyUri = + UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256\0"); + + /* Set ChannelModule context */ + channelModule->newContext = UA_ChannelModule_New_Context; + channelModule->deleteContext = UA_ChannelModule_Delete_Context; + channelModule->setLocalSymSigningKey = + UA_ChannelModule_Basic256Sha256_setLocalSymSigningKey; + channelModule->setLocalSymEncryptingKey = + UA_ChannelM_Basic256Sha256_setLocalSymEncryptingKey; + channelModule->setLocalSymIv = UA_ChannelM_Basic256Sha256_setLocalSymIv; + channelModule->setRemoteSymSigningKey = + UA_ChannelM_Basic256Sha256_setRemoteSymSigningKey; + channelModule->setRemoteSymEncryptingKey = + UA_ChannelM_Basic256Sha256_setRemoteSymEncryptingKey; + channelModule->setRemoteSymIv = UA_ChannelM_Basic256Sha256_setRemoteSymIv; + channelModule->compareCertificate = UA_ChannelM_Basic256Sha256_compareCertificate; UA_StatusCode retval = - UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, localPrivateKey, &config->logger); - if(retval != UA_STATUSCODE_GOOD) { - if(config->securityPoliciesSize == 0) { - UA_free(config->securityPolicies); - config->securityPolicies = NULL; - } + UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); + if(retval != UA_STATUSCODE_GOOD) return retval; - } - config->securityPoliciesSize++; - return UA_STATUSCODE_GOOD; -} + /* AsymmetricModule - signature algorithm */ + UA_SecurityPolicySignatureAlgorithm *asySigAlgorithm = + &asymmetricModule->cryptoModule.signatureAlgorithm; + asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0"); + asySigAlgorithm->verify = UA_AsySig_Basic256Sha256_Verify; + asySigAlgorithm->sign = UA_AsySig_Basic256Sha256_sign; + asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic256Sha256_getLocalSignatureSize; + asySigAlgorithm->getRemoteSignatureSize = UA_Asym_Basic256Sha256_getRemoteSignatureSize; + asySigAlgorithm->getLocalKeyLength = NULL; + asySigAlgorithm->getRemoteKeyLength = NULL; -/* Always returns UA_STATUSCODE_GOOD. Logs a warning if policies could not be added. */ -UA_EXPORT UA_StatusCode -UA_ServerConfig_addAllSecurityPolicies(UA_ServerConfig *config, - const UA_ByteString *certificate, - const UA_ByteString *privateKey) { - /* Populate the SecurityPolicies */ - UA_ByteString localCertificate = UA_BYTESTRING_NULL; - UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; - if(certificate) - localCertificate = *certificate; - if(privateKey) - localPrivateKey = *privateKey; + /* AsymmetricModule encryption algorithm */ + UA_SecurityPolicyEncryptionAlgorithm *asymEncryAlg = + &asymmetricModule->cryptoModule.encryptionAlgorithm; + asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); + asymEncryAlg->encrypt = UA_AsymEn_Basic256Sha256_encrypt; + asymEncryAlg->decrypt = UA_Asym_Basic256Sha256_Decrypt; + asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic256Sha256_getLocalKeyLength; + asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic256Sha256_getRemoteKeyLength; + asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic256Sha256_getRemoteBlockSize; + asymEncryAlg->getRemotePlainTextBlockSize = + UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize; - UA_StatusCode retval = UA_ServerConfig_addSecurityPolicyNone(config, &localCertificate); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#None with error code %s", - UA_StatusCode_name(retval)); - } + /* AsymmetricModule */ + asymmetricModule->compareCertificateThumbprint = UA_compareCertificateThumbprint; + asymmetricModule->makeCertificateThumbprint = UA_makeCertificateThumbprint; - retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &localCertificate, &localPrivateKey); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", - UA_StatusCode_name(retval)); - } + /* SymmetricModule */ + symmetricModule->secureChannelNonceLength = 32; + symmetricModule->generateNonce = UA_Sym_Basic256Sha256_generateNonce; + symmetricModule->generateKey = UA_Sym_Basic256Sha256_generateKey; - retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &localCertificate, &localPrivateKey); - if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic256 with error code %s", - UA_StatusCode_name(retval)); - } + /* Symmetric encryption Algorithm */ + UA_SecurityPolicyEncryptionAlgorithm *symEncryptionAlgorithm = + &symmetricModule->cryptoModule.encryptionAlgorithm; + symEncryptionAlgorithm->uri = + UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0"); + symEncryptionAlgorithm->encrypt = UA_SymEn_Basic256Sha256_encrypt; + symEncryptionAlgorithm->decrypt = UA_SymEn_Basic256Sha256_decrypt; + symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic256Sha256_getLocalKeyLength; + symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic256Sha256_getRemoteKeyLength; + symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic256Sha256_getBlockSize; + symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic256Sha256_getBlockSize; - retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &localCertificate, &localPrivateKey); + /* Symmetric signature Algorithm */ + UA_SecurityPolicySignatureAlgorithm *symSignatureAlgorithm = + &symmetricModule->cryptoModule.signatureAlgorithm; + symSignatureAlgorithm->uri = + UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0"); + symSignatureAlgorithm->verify = UA_SymSig_Basic256Sha256_verify; + symSignatureAlgorithm->sign = UA_SymSig_Basic256Sha256_sign; + symSignatureAlgorithm->getLocalSignatureSize = + UA_SymSig_Basic256Sha256_getLocalSignatureSize; + symSignatureAlgorithm->getRemoteSignatureSize = + UA_SymSig_Basic256Sha256_getRemoteSignatureSize; + symSignatureAlgorithm->getLocalKeyLength = + UA_SymSig_Basic256Sha256_getLocalKeyLength; + symSignatureAlgorithm->getRemoteKeyLength = + UA_SymSig_Basic256Sha256_getRemoteKeyLength; + + policy->clear = UA_Policy_Clear_Context; + retval = UA_Policy_New_Context(policy, localPrivateKey, logger); if(retval != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic256Sha256 with error code %s", - UA_StatusCode_name(retval)); + UA_ByteString_clear(&policy->localCertificate); + return retval; } + /* Use the same signature algorithm as the asymmetric component for + * certificate signing (see standard) */ + policy->certificateSigningAlgorithm = + policy->asymmetricModule.cryptoModule.signatureAlgorithm; + return UA_STATUSCODE_GOOD; } -UA_EXPORT UA_StatusCode -UA_ServerConfig_setDefaultWithSecurityPolicies(UA_ServerConfig *conf, - UA_UInt16 portNumber, - const UA_ByteString *certificate, - const UA_ByteString *privateKey, - const UA_ByteString *trustList, - size_t trustListSize, - const UA_ByteString *issuerList, - size_t issuerListSize, - const UA_ByteString *revocationList, - size_t revocationListSize) { - UA_StatusCode retval = setDefaultConfig(conf); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(conf); - return retval; - } +#endif - retval = UA_CertificateVerification_Trustlist(&conf->certificateVerification, - trustList, trustListSize, - issuerList, issuerListSize, - revocationList, revocationListSize); - if (retval != UA_STATUSCODE_GOOD) - return retval; +/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_aes128sha256rsaoaep.c" ****/ - retval = addDefaultNetworkLayers(conf, portNumber, 0, 0); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(conf); - return retval; - } +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Wind River Systems, Inc. + */ - retval = UA_ServerConfig_addAllSecurityPolicies(conf, certificate, privateKey); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(conf); - return retval; + +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) + + +#include <openssl/hmac.h> +#include <openssl/sha.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> +#include <openssl/rand.h> +#include <openssl/rsa.h> + +#define UA_SHA256_LENGTH 32 /* 256 bit */ +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN 42 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH 32 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH 16 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH 256 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH 512 + +typedef struct { + EVP_PKEY *localPrivateKey; + UA_ByteString localCertThumbprint; + const UA_Logger *logger; +} Policy_Context_Aes128Sha256RsaOaep; + +typedef struct { + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; + + Policy_Context_Aes128Sha256RsaOaep *policyContext; + UA_ByteString remoteCertificate; + X509 *remoteCertificateX509; /* X509 */ +} Channel_Context_Aes128Sha256RsaOaep; + +/* create the policy context */ + +static UA_StatusCode +UA_Policy_Aes128Sha256RsaOaep_New_Context(UA_SecurityPolicy *securityPolicy, + const UA_ByteString localPrivateKey, + const UA_Logger *logger) { + Policy_Context_Aes128Sha256RsaOaep *context = + (Policy_Context_Aes128Sha256RsaOaep *)UA_malloc( + sizeof(Policy_Context_Aes128Sha256RsaOaep)); + if(context == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; } - retval = UA_AccessControl_default(conf, true, - &conf->securityPolicies[conf->securityPoliciesSize-1].policyUri, - usernamePasswordsSize, usernamePasswords); - if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(conf); - return retval; + context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); + if (!context->localPrivateKey) { + UA_free(context); + return UA_STATUSCODE_BADINVALIDARGUMENT; } - retval = UA_ServerConfig_addAllEndpoints(conf); + UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint( + &securityPolicy->localCertificate, &context->localCertThumbprint, true); if(retval != UA_STATUSCODE_GOOD) { - UA_ServerConfig_clean(conf); + EVP_PKEY_free(context->localPrivateKey); + UA_free(context); return retval; } + context->logger = logger; + securityPolicy->policyContext = context; + return UA_STATUSCODE_GOOD; } -#endif +/* clear the policy context */ -/***************************/ -/* Default Client Settings */ -/***************************/ +static void +UA_Policy_Aes128Sha256RsaOaep_Clear_Context(UA_SecurityPolicy *policy) { + if(policy == NULL) + return; -UA_Client * UA_Client_new() { - UA_ClientConfig config; - memset(&config, 0, sizeof(UA_ClientConfig)); - config.logger.log = UA_Log_Stdout_log; - config.logger.context = NULL; - config.logger.clear = UA_Log_Stdout_clear; - return UA_Client_newWithConfig(&config); -} + UA_ByteString_clear(&policy->localCertificate); -UA_StatusCode -UA_ClientConfig_setDefault(UA_ClientConfig *config) { - config->timeout = 5000; - config->secureChannelLifeTime = 10 * 60 * 1000; /* 10 minutes */ + /* delete all allocated members in the context */ - if(!config->logger.log) { - config->logger.log = UA_Log_Stdout_log; - config->logger.context = NULL; - config->logger.clear = UA_Log_Stdout_clear; + Policy_Context_Aes128Sha256RsaOaep *pc = + (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext; + if (pc == NULL) { + return; } - config->localConnectionConfig = UA_ConnectionConfig_default; + EVP_PKEY_free(pc->localPrivateKey); + UA_ByteString_clear(&pc->localCertThumbprint); + UA_free(pc); - /* Certificate Verification that accepts every certificate. Can be - * overwritten when the policy is specialized. */ - UA_CertificateVerification_AcceptAll(&config->certificateVerification); - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "AcceptAll Certificate Verification. " - "Any remote certificate will be accepted."); + return; +} - /* With encryption enabled, the applicationUri needs to match the URI from - * the certificate */ - config->clientDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI); - config->clientDescription.applicationType = UA_APPLICATIONTYPE_CLIENT; +/* create the channel context */ - if(config->securityPoliciesSize > 0) { - UA_LOG_ERROR(&config->logger, UA_LOGCATEGORY_NETWORK, - "Could not initialize a config that already has SecurityPolicies"); +static UA_StatusCode +UA_ChannelModule_Aes128Sha256RsaOaep_New_Context(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **channelContext) { + if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL) { return UA_STATUSCODE_BADINTERNALERROR; } - - config->securityPolicies = (UA_SecurityPolicy*)UA_malloc(sizeof(UA_SecurityPolicy)); - if(!config->securityPolicies) + Channel_Context_Aes128Sha256RsaOaep *context = + (Channel_Context_Aes128Sha256RsaOaep *)UA_malloc( + sizeof(Channel_Context_Aes128Sha256RsaOaep)); + if(context == NULL) { return UA_STATUSCODE_BADOUTOFMEMORY; - UA_StatusCode retval = UA_SecurityPolicy_None(config->securityPolicies, - UA_BYTESTRING_NULL, &config->logger); + } + + UA_ByteString_init(&context->localSymSigningKey); + UA_ByteString_init(&context->localSymEncryptingKey); + UA_ByteString_init(&context->localSymIv); + UA_ByteString_init(&context->remoteSymSigningKey); + UA_ByteString_init(&context->remoteSymEncryptingKey); + UA_ByteString_init(&context->remoteSymIv); + + UA_StatusCode retval = + UA_copyCertificate(&context->remoteCertificate, remoteCertificate); if(retval != UA_STATUSCODE_GOOD) { - UA_free(config->securityPolicies); - config->securityPolicies = NULL; + UA_free(context); return retval; } - config->securityPoliciesSize = 1; - config->initConnectionFunc = UA_ClientConnectionTCP_init; /* for async client */ - config->pollConnectionFunc = UA_ClientConnectionTCP_poll; /* for async connection */ - - config->customDataTypes = NULL; - config->stateCallback = NULL; - config->connectivityCheckInterval = 0; + /* decode to X509 */ + context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); + if (context->remoteCertificateX509 == NULL) { + UA_ByteString_clear (&context->remoteCertificate); + UA_free (context); + return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + } - config->requestedSessionTimeout = 1200000; /* requestedSessionTimeout */ + context->policyContext = + (Policy_Context_Aes128Sha256RsaOaep *)(securityPolicy->policyContext); - config->inactivityCallback = NULL; - config->clientContext = NULL; + *channelContext = context; -#ifdef UA_ENABLE_SUBSCRIPTIONS - config->outStandingPublishRequests = 10; - config->subscriptionInactivityCallback = NULL; -#endif + UA_LOG_INFO( + securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The Aes128Sha256RsaOaep security policy channel with openssl is created."); return UA_STATUSCODE_GOOD; } -#ifdef UA_ENABLE_ENCRYPTION -UA_StatusCode -UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config, - UA_ByteString localCertificate, UA_ByteString privateKey, - const UA_ByteString *trustList, size_t trustListSize, - const UA_ByteString *revocationList, size_t revocationListSize) { - UA_StatusCode retval = UA_ClientConfig_setDefault(config); - if(retval != UA_STATUSCODE_GOOD) - return retval; - - retval = UA_CertificateVerification_Trustlist(&config->certificateVerification, - trustList, trustListSize, - NULL, 0, - revocationList, revocationListSize); - if(retval != UA_STATUSCODE_GOOD) - return retval; +/* delete the channel context */ - /* Populate SecurityPolicies */ - UA_SecurityPolicy *sp = (UA_SecurityPolicy*) - UA_realloc(config->securityPolicies, sizeof(UA_SecurityPolicy) * 4); - if(!sp) - return UA_STATUSCODE_BADOUTOFMEMORY; - config->securityPolicies = sp; - - retval = UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, privateKey, &config->logger); - if(retval == UA_STATUSCODE_GOOD) { - ++config->securityPoliciesSize; - } else { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", - UA_StatusCode_name(retval)); +static void +UA_ChannelModule_Aes128Sha256RsaOaep_Delete_Context(void *channelContext) { + if(channelContext != NULL) { + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + X509_free(cc->remoteCertificateX509); + UA_ByteString_clear(&cc->remoteCertificate); + UA_ByteString_clear(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymIv); + UA_ByteString_clear(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymIv); + + UA_LOG_INFO( + cc->policyContext->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The Aes128Sha256RsaOaep security policy channel with openssl is deleted."); + UA_free(cc); } +} - retval = UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, privateKey, &config->logger); - if(retval == UA_STATUSCODE_GOOD) { - ++config->securityPoliciesSize; - } else { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic256 with error code %s", - UA_StatusCode_name(retval)); - } +/* Verifies the signature of the message using the provided keys in the context. + * AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 + */ - retval = UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize], - localCertificate, privateKey, &config->logger); - if(retval == UA_STATUSCODE_GOOD) { - ++config->securityPoliciesSize; - } else { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, - "Could not add SecurityPolicy#Basic256Sha256 with error code %s", - UA_StatusCode_name(retval)); +static UA_StatusCode +UA_AsySig_Aes128Sha256RsaOaep_Verify(void *channelContext, const UA_ByteString *message, + const UA_ByteString *signature) { + if(message == NULL || signature == NULL || channelContext == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; } - if(config->securityPoliciesSize == 0) { - UA_free(config->securityPolicies); - config->securityPolicies = NULL; - } + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify( + message, cc->remoteCertificateX509, signature); - return UA_STATUSCODE_GOOD; + return retval; } -#endif - -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/ua_securitypolicy_none.c" ***********************************/ -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. - * - * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB - * Copyright 2017 (c) Stefan Profanter, fortiss GmbH +/* Compares the supplied certificate with the certificate + * in the endpoint context */ - static UA_StatusCode -verify_none(const UA_SecurityPolicy *securityPolicy, - void *channelContext, - const UA_ByteString *message, - const UA_ByteString *signature) { +UA_compareCertificateThumbprint_Aes128Sha256RsaOaep(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) { + if(securityPolicy == NULL || certificateThumbprint == NULL) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + Policy_Context_Aes128Sha256RsaOaep *pc = + (Policy_Context_Aes128Sha256RsaOaep *)securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) + return UA_STATUSCODE_BADCERTIFICATEINVALID; return UA_STATUSCODE_GOOD; } +/* Generates a thumbprint for the specified certificate */ + static UA_StatusCode -sign_none(const UA_SecurityPolicy *securityPolicy, - void *channelContext, - const UA_ByteString *message, - UA_ByteString *signature) { - return UA_STATUSCODE_GOOD; +UA_makeCertificateThumbprint_Aes128Sha256RsaOaep(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificate, + UA_ByteString *thumbprint) { + return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false); +} + +static UA_StatusCode +UA_Asym_Aes128Sha256RsaOaep_Decrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + Channel_Context_Aes128Sha256RsaOaep *cc = (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_StatusCode ret = UA_Openssl_RSA_Oaep_Decrypt(data, cc->policyContext->localPrivateKey); + return ret; } static size_t -length_none(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - return 0; +UA_Asym_Aes128Sha256RsaOaep_getRemoteSignatureSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t)keyLen; +} + +static size_t +UA_AsySig_Aes128Sha256RsaOaep_getLocalSignatureSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + Policy_Context_Aes128Sha256RsaOaep *pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen); + return (size_t)keyLen; +} + +static size_t +UA_AsymEn_Aes128Sha256RsaOaep_getRemotePlainTextBlockSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Aes128Sha256RsaOaep *cc = + (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t)keyLen - UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN; +} + +static size_t +UA_AsymEn_Aes128Sha256RsaOaep_getRemoteBlockSize(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Aes128Sha256RsaOaep *cc = + (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t)keyLen; +} + +static size_t +UA_AsymEn_Aes128Sha256RsaOaep_getRemoteKeyLength(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Aes128Sha256RsaOaep *cc = + (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); + return (size_t)keyLen * 8; } static UA_StatusCode -encrypt_none(const UA_SecurityPolicy *securityPolicy, - void *channelContext, - UA_ByteString *data) { +UA_Sym_Aes128Sha256RsaOaep_generateNonce(void *policyContext, + UA_ByteString *out) { + UA_Int32 rc = RAND_bytes(out->data, (int)out->length); + if(rc != 1) { + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } return UA_STATUSCODE_GOOD; } +static size_t +UA_SymEn_Aes128Sha256RsaOaep_getLocalKeyLength(const void *channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH; +} + +static size_t +UA_SymSig_Aes128Sha256RsaOaep_getLocalKeyLength(const void *channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH; +} + static UA_StatusCode -decrypt_none(const UA_SecurityPolicy *securityPolicy, - void *channelContext, - UA_ByteString *data) { - return UA_STATUSCODE_GOOD; +UA_Sym_Aes128Sha256RsaOaep_generateKey(void *policyContext, + const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out); } static UA_StatusCode -makeThumbprint_none(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *certificate, - UA_ByteString *thumbprint) { - return UA_STATUSCODE_GOOD; +UA_ChannelModule_Aes128Sha256RsaOaep_setLocalSymSigningKey(void *channelContext, + const UA_ByteString *key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_ByteString_clear(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); } static UA_StatusCode -compareThumbprint_none(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *certificateThumbprint) { - return UA_STATUSCODE_GOOD; +UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymEncryptingKey(void *channelContext, + const UA_ByteString *key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_ByteString_clear(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); } static UA_StatusCode -generateKey_none(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *secret, - const UA_ByteString *seed, - UA_ByteString *out) { - return UA_STATUSCODE_GOOD; +UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymIv(void *channelContext, + const UA_ByteString *iv) { + if(iv == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_ByteString_clear(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); +} + +static size_t +UA_SymEn_Aes128Sha256RsaOaep_getRemoteKeyLength(const void *channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH; +} + +static size_t +UA_SymEn_Aes128Sha256RsaOaep_getBlockSize(const void *channelContext) { + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE; +} + +static size_t +UA_SymSig_Aes128Sha256RsaOaep_getRemoteKeyLength(const void *channelContext) { + /* 32 bytes 256 bits */ + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH; } -/* Use the non-cryptographic RNG to set the nonce */ static UA_StatusCode -generateNonce_none(const UA_SecurityPolicy *securityPolicy, UA_ByteString *out) { - if(securityPolicy == NULL || out == NULL) +UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymSigningKey(void *channelContext, + const UA_ByteString *key) { + if(key == NULL || channelContext == NULL) return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_ByteString_clear(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +} - if(out->length == 0) - return UA_STATUSCODE_GOOD; +static UA_StatusCode +UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymEncryptingKey(void *channelContext, + const UA_ByteString *key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +} - /* Fill blocks of four byte */ - size_t i = 0; - while(i + 3 < out->length) { - UA_UInt32 randNumber = UA_UInt32_random(); - memcpy(&out->data[i], &randNumber, 4); - i = i+4; - } +static UA_StatusCode +UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymIv(void *channelContext, + const UA_ByteString *key) { + if(key == NULL || channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + UA_ByteString_clear(&cc->remoteSymIv); + return UA_ByteString_copy(key, &cc->remoteSymIv); +} - /* Fill the remaining byte */ - UA_UInt32 randNumber = UA_UInt32_random(); - memcpy(&out->data[i], &randNumber, out->length % 4); +static UA_StatusCode +UA_AsySig_Aes128Sha256RsaOaep_sign(void *channelContext, const UA_ByteString *message, + UA_ByteString *signature) { + if(channelContext == NULL || message == NULL || + signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + Policy_Context_Aes128Sha256RsaOaep *pc = cc->policyContext; + return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature); +} - return UA_STATUSCODE_GOOD; +static UA_StatusCode +UA_AsymEn_Aes128Sha256RsaOaep_encrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + return UA_Openssl_RSA_OAEP_Encrypt( + data, UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN, + cc->remoteCertificateX509); +} + +static size_t +UA_SymSig_Aes128Sha256RsaOaep_getRemoteSignatureSize(const void *channelContext) { + return UA_SHA256_LENGTH; } static UA_StatusCode -newContext_none(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *remoteCertificate, - void **channelContext) { - return UA_STATUSCODE_GOOD; +UA_SymSig_Aes128Sha256RsaOaep_verify(void *channelContext, const UA_ByteString *message, + const UA_ByteString *signature) { + if(channelContext == NULL || message == NULL || + signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature); } -static void -deleteContext_none(void *channelContext) { +static UA_StatusCode +UA_SymSig_Aes128Sha256RsaOaep_sign(void *channelContext, const UA_ByteString *message, + UA_ByteString *signature) { + if(channelContext == NULL || message == NULL || + signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature); +} + +static size_t +UA_SymSig_Aes128Sha256RsaOaep_getLocalSignatureSize(const void *channelContext) { + return UA_SHA256_LENGTH; } static UA_StatusCode -setContextValue_none(void *channelContext, - const UA_ByteString *key) { - return UA_STATUSCODE_GOOD; +UA_SymEn_Aes128Sha256RsaOaep_decrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey, + data); } static UA_StatusCode -compareCertificate_none(const void *channelContext, - const UA_ByteString *certificate) { - return UA_STATUSCODE_GOOD; +UA_SymEn_Aes128Sha256RsaOaep_encrypt(void *channelContext, UA_ByteString *data) { + if(channelContext == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Channel_Context_Aes128Sha256RsaOaep *cc = + (Channel_Context_Aes128Sha256RsaOaep *)channelContext; + return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey, + data); } static UA_StatusCode -updateCertificateAndPrivateKey_none(UA_SecurityPolicy *policy, - const UA_ByteString newCertificate, - const UA_ByteString newPrivateKey) { - UA_ByteString_deleteMembers(&policy->localCertificate); - UA_ByteString_copy(&newCertificate, &policy->localCertificate); - return UA_STATUSCODE_GOOD; +UA_ChannelM_Aes128Sha256RsaOaep_compareCertificate(const void *channelContext, + const UA_ByteString *certificate) { + if(channelContext == NULL || certificate == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509); } +static size_t +UA_AsymEn_Aes128Sha256RsaOaep_getLocalKeyLength(const void *channelContext) { + if(channelContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -static void -policy_clear_none(UA_SecurityPolicy *policy) { - UA_ByteString_deleteMembers(&policy->localCertificate); + const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext; + Policy_Context_Aes128Sha256RsaOaep *pc = cc->policyContext; + UA_Int32 keyLen = 0; + UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen); + return (size_t)keyLen * 8; } +/* the main entry of Aes128Sha256RsaOaep */ + UA_StatusCode -UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate, - const UA_Logger *logger) { - policy->policyContext = (void *)(uintptr_t)logger; - policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); +UA_SecurityPolicy_Aes128Sha256RsaOaep(UA_SecurityPolicy *policy, + const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey, + const UA_Logger *logger) { + + UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule; + UA_StatusCode retval; + + UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURITYPOLICY, + "The Aes128Sha256RsaOaep security policy with openssl is added."); + + UA_Openssl_Init(); + memset(policy, 0, sizeof(UA_SecurityPolicy)); policy->logger = logger; - UA_ByteString_copy(&localCertificate, &policy->localCertificate); + policy->policyUri = + UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep\0"); - policy->symmetricModule.generateKey = generateKey_none; - policy->symmetricModule.generateNonce = generateNonce_none; + /* set ChannelModule context */ - UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm = - &policy->symmetricModule.cryptoModule.signatureAlgorithm; - sym_signatureAlgorithm->uri = UA_STRING_NULL; - sym_signatureAlgorithm->verify = verify_none; - sym_signatureAlgorithm->sign = sign_none; - sym_signatureAlgorithm->getLocalSignatureSize = length_none; - sym_signatureAlgorithm->getRemoteSignatureSize = length_none; - sym_signatureAlgorithm->getLocalKeyLength = length_none; - sym_signatureAlgorithm->getRemoteKeyLength = length_none; + channelModule->newContext = UA_ChannelModule_Aes128Sha256RsaOaep_New_Context; + channelModule->deleteContext = UA_ChannelModule_Aes128Sha256RsaOaep_Delete_Context; + channelModule->setLocalSymSigningKey = + UA_ChannelModule_Aes128Sha256RsaOaep_setLocalSymSigningKey; + channelModule->setLocalSymEncryptingKey = + UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymEncryptingKey; + channelModule->setLocalSymIv = UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymIv; + channelModule->setRemoteSymSigningKey = + UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymSigningKey; + channelModule->setRemoteSymEncryptingKey = + UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymEncryptingKey; + channelModule->setRemoteSymIv = UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymIv; + channelModule->compareCertificate = + UA_ChannelM_Aes128Sha256RsaOaep_compareCertificate; + + /* Copy the certificate and add a NULL to the end */ + + retval = UA_copyCertificate(&policy->localCertificate, &localCertificate); + if(retval != UA_STATUSCODE_GOOD) + return retval; - UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = - &policy->symmetricModule.cryptoModule.encryptionAlgorithm; - sym_encryptionAlgorithm->uri = UA_STRING_NULL; - sym_encryptionAlgorithm->encrypt = encrypt_none; - sym_encryptionAlgorithm->decrypt = decrypt_none; - sym_encryptionAlgorithm->getLocalKeyLength = length_none; - sym_encryptionAlgorithm->getRemoteKeyLength = length_none; - sym_encryptionAlgorithm->getLocalBlockSize = length_none; - sym_encryptionAlgorithm->getRemoteBlockSize = length_none; - sym_encryptionAlgorithm->getLocalPlainTextBlockSize = length_none; - sym_encryptionAlgorithm->getRemotePlainTextBlockSize = length_none; - policy->symmetricModule.secureChannelNonceLength = 0; + /* AsymmetricModule - signature algorithm */ - policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none; - policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none; + UA_SecurityPolicySignatureAlgorithm *asySigAlgorithm = + &asymmetricModule->cryptoModule.signatureAlgorithm; + asySigAlgorithm->uri = + UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0"); + asySigAlgorithm->verify = UA_AsySig_Aes128Sha256RsaOaep_Verify; + asySigAlgorithm->getRemoteSignatureSize = + UA_Asym_Aes128Sha256RsaOaep_getRemoteSignatureSize; + asySigAlgorithm->getLocalSignatureSize = + UA_AsySig_Aes128Sha256RsaOaep_getLocalSignatureSize; + asySigAlgorithm->sign = UA_AsySig_Aes128Sha256RsaOaep_sign; + asySigAlgorithm->getLocalKeyLength = NULL; + asySigAlgorithm->getRemoteKeyLength = NULL; - // This only works for none since symmetric and asymmetric crypto modules do the same i.e. nothing - policy->asymmetricModule.cryptoModule = policy->symmetricModule.cryptoModule; + /* AsymmetricModule encryption algorithm */ - // Use the same signing algorithm as for asymmetric signing - policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + UA_SecurityPolicyEncryptionAlgorithm *asymEncryAlg = + &asymmetricModule->cryptoModule.encryptionAlgorithm; + asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); + asymEncryAlg->decrypt = UA_Asym_Aes128Sha256RsaOaep_Decrypt; + asymEncryAlg->getRemotePlainTextBlockSize = + UA_AsymEn_Aes128Sha256RsaOaep_getRemotePlainTextBlockSize; + asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Aes128Sha256RsaOaep_getRemoteBlockSize; + asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Aes128Sha256RsaOaep_getRemoteKeyLength; + asymEncryAlg->encrypt = UA_AsymEn_Aes128Sha256RsaOaep_encrypt; + asymEncryAlg->getLocalKeyLength = UA_AsymEn_Aes128Sha256RsaOaep_getLocalKeyLength; - policy->channelModule.newContext = newContext_none; - policy->channelModule.deleteContext = deleteContext_none; - policy->channelModule.setLocalSymEncryptingKey = setContextValue_none; - policy->channelModule.setLocalSymSigningKey = setContextValue_none; - policy->channelModule.setLocalSymIv = setContextValue_none; - policy->channelModule.setRemoteSymEncryptingKey = setContextValue_none; - policy->channelModule.setRemoteSymSigningKey = setContextValue_none; - policy->channelModule.setRemoteSymIv = setContextValue_none; - policy->channelModule.compareCertificate = compareCertificate_none; - policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_none; - policy->clear = policy_clear_none; + /* asymmetricModule */ + + asymmetricModule->compareCertificateThumbprint = + UA_compareCertificateThumbprint_Aes128Sha256RsaOaep; + asymmetricModule->makeCertificateThumbprint = + UA_makeCertificateThumbprint_Aes128Sha256RsaOaep; + + /* SymmetricModule */ + + symmetricModule->secureChannelNonceLength = 32; + symmetricModule->generateNonce = UA_Sym_Aes128Sha256RsaOaep_generateNonce; + symmetricModule->generateKey = UA_Sym_Aes128Sha256RsaOaep_generateKey; + + /* Symmetric encryption Algorithm */ + + UA_SecurityPolicyEncryptionAlgorithm *symEncryptionAlgorithm = + &symmetricModule->cryptoModule.encryptionAlgorithm; + symEncryptionAlgorithm->uri = + UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0"); + symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Aes128Sha256RsaOaep_getLocalKeyLength; + symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Aes128Sha256RsaOaep_getRemoteKeyLength; + symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Aes128Sha256RsaOaep_getBlockSize; + symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Aes128Sha256RsaOaep_getBlockSize; + symEncryptionAlgorithm->decrypt = UA_SymEn_Aes128Sha256RsaOaep_decrypt; + symEncryptionAlgorithm->encrypt = UA_SymEn_Aes128Sha256RsaOaep_encrypt; + + /* Symmetric signature Algorithm */ + + UA_SecurityPolicySignatureAlgorithm *symSignatureAlgorithm = + &symmetricModule->cryptoModule.signatureAlgorithm; + symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0"); + symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Aes128Sha256RsaOaep_getLocalKeyLength; + symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Aes128Sha256RsaOaep_getRemoteKeyLength; + symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Aes128Sha256RsaOaep_getRemoteSignatureSize; + symSignatureAlgorithm->verify = UA_SymSig_Aes128Sha256RsaOaep_verify; + symSignatureAlgorithm->sign = UA_SymSig_Aes128Sha256RsaOaep_sign; + symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Aes128Sha256RsaOaep_getLocalSignatureSize; + + retval = UA_Policy_Aes128Sha256RsaOaep_New_Context(policy, localPrivateKey, logger); + if(retval != UA_STATUSCODE_GOOD) { + UA_ByteString_clear(&policy->localCertificate); + return retval; + } + policy->clear = UA_Policy_Aes128Sha256RsaOaep_Clear_Context; + + /* Use the same signature algorithm as the asymmetric component for + certificate signing (see standard) */ + + policy->certificateSigningAlgorithm = + policy->asymmetricModule.cryptoModule.signatureAlgorithm; return UA_STATUSCODE_GOOD; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/ua_log_syslog.c" ***********************************/ +#endif + +/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_create_certificate.c" ****/ -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + * Copyright 2022 (c) Wind River Systems, Inc. * - * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) */ -#if defined(__linux__) || defined(__unix__) -#include <syslog.h> +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) -const char *syslogLevelNames[6] = {"trace", "debug", "info", - "warn", "error", "fatal"}; -const char *syslogCategoryNames[7] = {"network", "channel", "session", "server", - "client", "userland", "securitypolicy"}; -#ifdef __clang__ -__attribute__((__format__(__printf__, 4 , 0))) -#endif -static void -UA_Log_Syslog_log(void *context, UA_LogLevel level, UA_LogCategory category, - const char *msg, va_list args) { - /* Assume that context is casted to UA_LogLevel */ - if(context != NULL && (UA_LogLevel)(uintptr_t)context > level) - return; +#include <openssl/pem.h> +#include <openssl/x509v3.h> - int priority = LOG_INFO; - switch(level) { - case UA_LOGLEVEL_DEBUG: - priority = LOG_DEBUG; - break; - case UA_LOGLEVEL_INFO: - priority = LOG_INFO; - break; - case UA_LOGLEVEL_WARNING: - priority = LOG_WARNING; - break; - case UA_LOGLEVEL_ERROR: - priority = LOG_ERR; - break; - case UA_LOGLEVEL_FATAL: - priority = LOG_CRIT; - break; - case UA_LOGLEVEL_TRACE: - default: - return; +/** + * Join an array of UA_String to a single NULL-Terminated UA_String + * separated by character sep + */ +static UA_StatusCode +join_string_with_sep(const UA_String *strings, size_t stringsSize, + char sep, UA_String *out) { + if(!out) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + UA_String_clear(out); + size_t totalSize = stringsSize; + for(size_t iStr = 0; iStr < stringsSize; ++iStr) { + totalSize += strings[iStr].length; } -#define LOGBUFSIZE 512 - char logbuf[LOGBUFSIZE]; - int pos = snprintf(logbuf, LOGBUFSIZE, "[%s/%s] ", - syslogLevelNames[level], syslogCategoryNames[category]); - if(pos < 0) { - syslog(LOG_WARNING, "Log message too long for syslog"); - return; + UA_ByteString_allocBuffer(out, totalSize); + if(!out->data) { + return UA_STATUSCODE_BADOUTOFMEMORY; } - pos = vsnprintf(&logbuf[pos], LOGBUFSIZE - (size_t)pos, msg, args); - if(pos < 0) { - syslog(LOG_WARNING, "Log message too long for syslog"); - return; + + size_t pos = 0; + for(size_t iStr = 0; iStr < stringsSize; ++iStr) { + memcpy(&out->data[pos], strings[iStr].data, strings[iStr].length); + pos += strings[iStr].length; + out->data[pos] = (UA_Byte) sep; + ++pos; } + out->data[out->length-1] = 0; - syslog(priority, "%s", logbuf); + return UA_STATUSCODE_GOOD; } -static void -UA_Log_Syslog_clear(void *logContext) { - /* closelog is optional. We don't use it as several loggers might be - * instantiated in parallel. */ - /* closelog(); */ +/** + * Search for a character in a string (like strchr). + * \todo Handle UTF-8 + * + * \return index of the character or -1 on case of an error. + */ + +static UA_Int32 +UA_String_chr(const UA_String *pUaStr, char needl) { + UA_Byte byteNeedl = (UA_Byte)needl; + for(size_t i = 0; (size_t)i < pUaStr->length; ++i) { + if(pUaStr->data[i] == byteNeedl) { + return (UA_Int32) i; + } + } + return -1; } -UA_Logger -UA_Log_Syslog(void) { - return UA_Log_Syslog_withLevel(UA_LOGLEVEL_TRACE); +static UA_StatusCode +add_x509V3ext(X509 *x509, int nid, const char *value) { + X509_EXTENSION *ex; + X509V3_CTX ctx; + X509V3_set_ctx_nodb(&ctx); + X509V3_set_ctx(&ctx, x509, x509, NULL, NULL, 0); + ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); + if(!ex) + return UA_STATUSCODE_BADINTERNALERROR; + X509_add_ext(x509, ex, -1); + X509_EXTENSION_free(ex); + return UA_STATUSCODE_GOOD; } -UA_Logger -UA_Log_Syslog_withLevel(UA_LogLevel minlevel) { - UA_Logger logger = {UA_Log_Syslog_log, (void*)minlevel, UA_Log_Syslog_clear}; - return logger; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + +/* generate the RSA key */ + +static EVP_PKEY * UA_RSA_Generate_Key (size_t keySizeBits){ + return EVP_RSA_gen(keySizeBits); } #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/securitypolicy_mbedtls_common.h" ***********************************/ +UA_StatusCode +UA_CreateCertificate(const UA_Logger *logger, + const UA_String *subject, size_t subjectSize, + const UA_String *subjectAltName, size_t subjectAltNameSize, + size_t keySizeBits, UA_CertificateFormat certFormat, + UA_ByteString *outPrivateKey, UA_ByteString *outCertificate) { + if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || + !subject || subjectAltNameSize == 0 || subjectSize == 0 || + (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM )) + return UA_STATUSCODE_BADINVALIDARGUMENT; -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. - * - * Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer) - */ + /* Use the maximum size */ + if(keySizeBits == 0) + keySizeBits = 4096; + UA_ByteString_init(outPrivateKey); + UA_ByteString_init(outCertificate); + UA_String fullAltSubj = UA_STRING_NULL; + UA_Int32 serial = 1; -#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS + /** \TODO: Seed Random generator + * See: (https://www.openssl.org/docs/man1.1.0/man3/RAND_add.html) */ + BIO *memCert = NULL; + BIO *memPKey = NULL; -#include <mbedtls/md.h> -#include <mbedtls/x509_crt.h> -#include <mbedtls/ctr_drbg.h> + UA_StatusCode errRet = UA_STATUSCODE_GOOD; + + X509 *x509 = X509_new(); -#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) -#define MBEDTLS_ENTROPY_POLL_METHOD mbedtls_platform_entropy_poll +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY *pkey = UA_RSA_Generate_Key(keySizeBits); + if((pkey == NULL) || (x509 == NULL)) { + errRet = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } #else -// MBEDTLS_ENTROPY_HARDWARE_ALT should be defined if your hardware does not supportd platform entropy -#define MBEDTLS_ENTROPY_POLL_METHOD mbedtls_hardware_poll -#endif + BIGNUM *exponent = BN_new(); + EVP_PKEY *pkey = EVP_PKEY_new(); + RSA *rsa = RSA_new(); + if(!pkey || !x509 || !exponent || !rsa) { + errRet = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } -#define UA_SHA1_LENGTH 20 + UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Generating RSA key. This may take a while."); -_UA_BEGIN_DECLS + if(BN_set_word(exponent, RSA_F4) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting RSA exponent failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -void -swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB); + if(RSA_generate_key_ex(rsa, (int) keySizeBits, exponent, NULL) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Generating RSA key failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -void -mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key, - const UA_ByteString *in, unsigned char *out); + if(EVP_PKEY_assign_RSA(pkey, rsa) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Assign RSA key failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + /* rsa will be freed by pkey */ + rsa = NULL; -UA_StatusCode -mbedtls_generateKey(mbedtls_md_context_t *context, - const UA_ByteString *secret, const UA_ByteString *seed, - UA_ByteString *out); +#endif /* end of OPENSSL_VERSION_NUMBER >= 0x30000000L */ -UA_StatusCode -mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message, - const UA_ByteString *signature); + /* x509v3 has version 2 + * (https://www.openssl.org/docs/man1.1.0/man3/X509_set_version.html) */ + if(X509_set_version(x509, 2) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting version failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -UA_StatusCode -mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey, - mbedtls_ctr_drbg_context *drbgContext, - const UA_ByteString *message, - UA_ByteString *signature); + if(ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting serial number failed."); + /* Only memory errors are possible */ + errRet = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } -UA_StatusCode -mbedtls_thumbprint_sha1(const UA_ByteString *certificate, - UA_ByteString *thumbprint); + if(X509_gmtime_adj(X509_get_notBefore(x509), 0) == NULL) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'not before' failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -/* Set the hashing scheme before calling - * E.g. mbedtls_rsa_set_padding(context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); */ -UA_StatusCode -mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context, - mbedtls_ctr_drbg_context *drbgContext, - UA_ByteString *data, const size_t plainTextBlockSize); + if(X509_gmtime_adj(X509_get_notAfter(x509), (UA_Int64) 60 * 60 * 24 * 365) == NULL) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'not before' failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -UA_StatusCode -mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey, - mbedtls_ctr_drbg_context *drbgContext, - UA_ByteString *data); + if(X509_set_pubkey(x509, pkey) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting publik key failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -int UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target); + X509_NAME *name = X509_get_subject_name(x509); + if(name == NULL) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Getting name failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -UA_StatusCode UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData, UA_ByteString *target); + for(UA_UInt32 iSubject = 0; iSubject < subjectSize; ++iSubject) { + UA_Int32 sep = UA_String_chr(&subject[iSubject], '='); + char field[16]; + if(sep == -1 || sep == 0 || + ((size_t) sep == (subject[iSubject].length - 1)) || sep >= 15) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Subject must contain one '=' with " + "content before and after."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + memcpy(field, subject[iSubject].data, (size_t) sep); + field[sep] = 0; + UA_Byte* pData = &subject[iSubject].data[sep + 1]; + if(X509_NAME_add_entry_by_txt( + name, field, MBSTRING_ASC, + (const unsigned char *)pData, + (int) subject[iSubject].length - (int) sep - 1, -1, 0) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting subject failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + } + /* Self signed, so issuer == subject */ + if(X509_set_issuer_name(x509, name) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting name failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } -UA_ByteString UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data); + errRet = add_x509V3ext(x509, NID_basic_constraints, "CA:FALSE"); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'Basic Constraints' failed."); + goto cleanup; + } -_UA_END_DECLS + /* See https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 for + * possible values */ + errRet = add_x509V3ext(x509, NID_key_usage, + "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyCertSign"); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'Key Usage' failed."); + goto cleanup; + } + + errRet = add_x509V3ext(x509, NID_ext_key_usage, "serverAuth,clientAuth"); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'Extended Key Usage' failed."); + goto cleanup; + } + + errRet = add_x509V3ext(x509, NID_subject_key_identifier, "hash"); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'Subject Key Identifier' failed."); + goto cleanup; + } + + errRet = join_string_with_sep(subjectAltName, subjectAltNameSize, ',', &fullAltSubj); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Joining altSubject failed."); + goto cleanup; + } + + errRet = add_x509V3ext(x509, NID_subject_alt_name, (const char*) fullAltSubj.data); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Setting 'Subject Alternative Name:' failed."); + goto cleanup; + } + + if(X509_sign(x509, pkey, EVP_sha256()) == 0) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Signing failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + + switch(certFormat) { + case UA_CERTIFICATEFORMAT_DER: { + int tmpLen = i2d_PrivateKey(pkey, &outPrivateKey->data); + if(tmpLen <= 0) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Create private DER key failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + outPrivateKey->length = (size_t) tmpLen; + tmpLen = i2d_X509(x509, &outCertificate->data); + if(tmpLen <= 0) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Create DER-certificate failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + outCertificate->length = (size_t) tmpLen; + break; + } + case UA_CERTIFICATEFORMAT_PEM: { + /* Private Key */ + memPKey = BIO_new(BIO_s_mem()); + if(!memPKey) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Allocate Membuffer for PKey failed."); + errRet = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } + + if(PEM_write_bio_PrivateKey(memPKey, pkey, NULL, NULL, 0, 0, NULL) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Generate PEM-PrivateKey failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + + UA_ByteString tmpPem = UA_BYTESTRING_NULL; + tmpPem.length = (size_t) BIO_get_mem_data(memPKey, &tmpPem.data); + errRet = UA_ByteString_copy(&tmpPem, outPrivateKey); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Copy PEM PKey failed."); + goto cleanup; + } + + /* Certificate */ + memCert = BIO_new(BIO_s_mem()); + if(!memCert) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Allocate Membuffer for Cert failed."); + errRet = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } + + if(PEM_write_bio_X509(memCert, x509) != 1) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Generate PEM-Certifcate failed."); + errRet = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + + tmpPem.length = (size_t) BIO_get_mem_data(memCert, &tmpPem.data); + errRet = UA_ByteString_copy(&tmpPem, outCertificate); + if(errRet != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL, + "Create Certificate: Copy PEM Certificate failed."); + goto cleanup; + } + break; + } + } + +cleanup: + UA_String_clear(&fullAltSubj); +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA_free(rsa); + BN_free(exponent); #endif + X509_free(x509); + EVP_PKEY_free(pkey); + BIO_free(memCert); + BIO_free(memPKey); + return errRet; +} +#endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/securitypolicy_mbedtls_common.c" ***********************************/ +/**** amalgamated original file "/plugins/crypto/openssl/ua_pki_openssl.c" ****/ +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2020 (c) Wind River Systems, Inc. + * Copyright 2020 (c) basysKom GmbH -#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS + */ -#include <mbedtls/aes.h> -#include <mbedtls/ctr_drbg.h> -#include <mbedtls/entropy.h> -#include <mbedtls/entropy_poll.h> -#include <mbedtls/error.h> -#include <mbedtls/md.h> -#include <mbedtls/sha1.h> -#include <mbedtls/version.h> -#include <mbedtls/x509_crt.h> -void -swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) { - UA_ByteString tmp = *bufA; - *bufA = *bufB; - *bufB = tmp; +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) +#include <openssl/x509.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509v3.h> +#include <openssl/pem.h> + + +/* Find binary substring. Taken and adjusted from + * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */ + +static const unsigned char * +bstrchr(const unsigned char *s, const unsigned char ch, size_t l) { + /* find first occurrence of c in char s[] for length l*/ + for(; l > 0; ++s, --l) { + if(*s == ch) + return s; + } + return NULL; } -void -mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key, - const UA_ByteString *in, unsigned char *out) { - mbedtls_md_hmac_starts(context, key->data, key->length); - mbedtls_md_hmac_update(context, in->data, in->length); - mbedtls_md_hmac_finish(context, out); +static const unsigned char * +UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) { + /* find first occurrence of s2[] in s1[] for length l1*/ + const unsigned char *ss1 = s1; + const unsigned char *ss2 = s2; + /* handle special case */ + if(l1 == 0) + return (NULL); + if(l2 == 0) + return s1; + + /* match prefix */ + for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL && + (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) { + + /* match rest of prefix */ + const unsigned char *sc1, *sc2; + for (sc1 = s1, sc2 = s2; ;) + if (++sc2 >= ss2+l2) + return s1; + else if (*++sc1 != *sc2) + break; + } + return NULL; } -UA_StatusCode -mbedtls_generateKey(mbedtls_md_context_t *context, - const UA_ByteString *secret, const UA_ByteString *seed, - UA_ByteString *out) { - size_t hashLen = (size_t)mbedtls_md_get_size(context->md_info); +typedef struct { + /* + * If the folders are defined, we use them to reload the certificates during + * runtime + */ - UA_ByteString A_and_seed; - UA_ByteString_allocBuffer(&A_and_seed, hashLen + seed->length); - memcpy(A_and_seed.data + hashLen, seed->data, seed->length); + UA_String trustListFolder; + UA_String issuerListFolder; + UA_String revocationListFolder; - UA_ByteString ANext_and_seed; - UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length); - memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length); + STACK_OF(X509) * skIssue; + STACK_OF(X509) * skTrusted; + STACK_OF(X509_CRL) * skCrls; /* Revocation list*/ +} CertContext; - UA_ByteString A = { - hashLen, - A_and_seed.data - }; +static UA_StatusCode +UA_CertContext_sk_Init (CertContext * context) { + context->skTrusted = sk_X509_new_null(); + context->skIssue = sk_X509_new_null(); + context->skCrls = sk_X509_CRL_new_null(); + if (context->skTrusted == NULL || context->skIssue == NULL || + context->skCrls == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + return UA_STATUSCODE_GOOD; +} - UA_ByteString ANext = { - hashLen, - ANext_and_seed.data - }; +static void +UA_CertContext_sk_free (CertContext * context) { + sk_X509_pop_free (context->skTrusted, X509_free); + sk_X509_pop_free (context->skIssue, X509_free); + sk_X509_CRL_pop_free (context->skCrls, X509_CRL_free); +} - mbedtls_hmac(context, secret, seed, A.data); +static UA_StatusCode +UA_CertContext_Init (CertContext * context) { + (void) memset (context, 0, sizeof (CertContext)); + UA_ByteString_init (&context->trustListFolder); + UA_ByteString_init (&context->issuerListFolder); + UA_ByteString_init (&context->revocationListFolder); + return UA_CertContext_sk_Init (context); +} - UA_StatusCode retval = 0; - for(size_t offset = 0; offset < out->length; offset += hashLen) { - UA_ByteString outSegment = { - hashLen, - out->data + offset - }; - UA_Boolean bufferAllocated = UA_FALSE; - // Not enough room in out buffer to write the hash. - if(offset + hashLen > out->length) { - outSegment.data = NULL; - outSegment.length = 0; - retval = UA_ByteString_allocBuffer(&outSegment, hashLen); - if(retval != UA_STATUSCODE_GOOD) { - UA_ByteString_deleteMembers(&A_and_seed); - UA_ByteString_deleteMembers(&ANext_and_seed); - return retval; - } - bufferAllocated = UA_TRUE; +static void +UA_CertificateVerification_clear (UA_CertificateVerification * cv) { + if (cv == NULL) { + return ; + } + CertContext * context = (CertContext *) cv->context; + if (context == NULL) { + return; + } + UA_ByteString_clear (&context->trustListFolder); + UA_ByteString_clear (&context->issuerListFolder); + UA_ByteString_clear (&context->revocationListFolder); + + UA_CertContext_sk_free (context); + UA_free (context); + + cv->context = NULL; + + return; +} + +static UA_StatusCode +UA_skTrusted_Cert2X509 (const UA_ByteString * certificateTrustList, + size_t certificateTrustListSize, + CertContext * ctx) { + size_t i; + + for (i = 0; i < certificateTrustListSize; i++) { + X509 * x509 = UA_OpenSSL_LoadCertificate(&certificateTrustList[i]); + + if (x509 == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; } + sk_X509_push (ctx->skTrusted, x509); + } - mbedtls_hmac(context, secret, &A_and_seed, outSegment.data); - mbedtls_hmac(context, secret, &A, ANext.data); + return UA_STATUSCODE_GOOD; +} - if(retval != UA_STATUSCODE_GOOD) { - if(bufferAllocated) - UA_ByteString_deleteMembers(&outSegment); - UA_ByteString_deleteMembers(&A_and_seed); - UA_ByteString_deleteMembers(&ANext_and_seed); - return retval; +static UA_StatusCode +UA_skIssuer_Cert2X509 (const UA_ByteString * certificateIssuerList, + size_t certificateIssuerListSize, + CertContext * ctx) { + size_t i; + + for (i = 0; i < certificateIssuerListSize; i++) { + X509 * x509 = UA_OpenSSL_LoadCertificate(&certificateIssuerList[i]); + + if (x509 == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; } + sk_X509_push (ctx->skIssue, x509); + } - if(bufferAllocated) { - memcpy(out->data + offset, outSegment.data, out->length - offset); - UA_ByteString_deleteMembers(&outSegment); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_skCrls_Cert2X509 (const UA_ByteString * certificateRevocationList, + size_t certificateRevocationListSize, + CertContext * ctx) { + size_t i; + const unsigned char * pData; + + for (i = 0; i < certificateRevocationListSize; i++) { + pData = certificateRevocationList[i].data; + X509_CRL * crl = NULL; + + if (certificateRevocationList[i].length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files + crl = d2i_X509_CRL (NULL, &pData, (long) certificateRevocationList[i].length); + } else { + BIO* bio = NULL; + bio = BIO_new_mem_buf((void *) certificateRevocationList[i].data, + (int) certificateRevocationList[i].length); + crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); + BIO_free(bio); } - swapBuffers(&ANext_and_seed, &A_and_seed); - swapBuffers(&ANext, &A); + if (crl == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } + sk_X509_CRL_push (ctx->skCrls, crl); } - UA_ByteString_deleteMembers(&A_and_seed); - UA_ByteString_deleteMembers(&ANext_and_seed); - return UA_STATUSCODE_GOOD; + return UA_STATUSCODE_GOOD; } -UA_StatusCode -mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message, - const UA_ByteString *signature) { - /* Compute the sha1 hash */ - unsigned char hash[UA_SHA1_LENGTH]; -#if MBEDTLS_VERSION_NUMBER >= 0x02070000 - mbedtls_sha1_ret(message->data, message->length, hash); -#else - mbedtls_sha1(message->data, message->length, hash); -#endif +#ifdef __linux__ +#include <dirent.h> - /* Set the RSA settings */ - mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(certificate->pk); - if(!rsaContext) - return UA_STATUSCODE_BADINTERNALERROR; - mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); +static int UA_Certificate_Filter_der_pem (const struct dirent * entry) { + /* ignore hidden files */ + if (entry->d_name[0] == '.') return 0; - /* Verify */ - int mbedErr = mbedtls_pk_verify(&certificate->pk, - MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH, - signature->data, signature->length); - if(mbedErr) - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - return UA_STATUSCODE_GOOD; + /* check file extension */ + const char *pszFind = strrchr(entry->d_name, '.'); + if (pszFind == 0) + return 0; + pszFind++; + if (strcmp (pszFind, "der") == 0 || strcmp (pszFind, "pem") == 0) + return 1; + + return 0; } -UA_StatusCode -mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey, - mbedtls_ctr_drbg_context *drbgContext, - const UA_ByteString *message, - UA_ByteString *signature) { - unsigned char hash[UA_SHA1_LENGTH]; -#if MBEDTLS_VERSION_NUMBER >= 0x02070000 - mbedtls_sha1_ret(message->data, message->length, hash); -#else - mbedtls_sha1(message->data, message->length, hash); -#endif +static int UA_Certificate_Filter_crl (const struct dirent * entry) { - mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey); - mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); + /* ignore hidden files */ + if (entry->d_name[0] == '.') return 0; + + /* check file extension */ + const char *pszFind = strrchr(entry->d_name, '.'); + if (pszFind == 0) + return 0; + pszFind++; + if (strcmp (pszFind, "crl") == 0) + return 1; + + return 0; +} + +static UA_StatusCode +UA_BuildFullPath (const char * path, + const char * fileName, + size_t fullPathBufferLength, + char * fullPath) { + size_t pathLen = strlen (path); + size_t fileNameLen = strlen (fileName); + if ((pathLen + fileNameLen + 2) > fullPathBufferLength) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + strcpy (fullPath, path); + strcat (fullPath, "/"); + strcat (fullPath, fileName); - size_t sigLen = 0; - int mbedErr = mbedtls_pk_sign(localPrivateKey, MBEDTLS_MD_SHA1, hash, - UA_SHA1_LENGTH, signature->data, &sigLen, - mbedtls_ctr_drbg_random, drbgContext); - if(mbedErr) - return UA_STATUSCODE_BADINTERNALERROR; return UA_STATUSCODE_GOOD; } -UA_StatusCode -mbedtls_thumbprint_sha1(const UA_ByteString *certificate, - UA_ByteString *thumbprint) { - if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL)) - return UA_STATUSCODE_BADINTERNALERROR; +static UA_StatusCode +UA_loadCertFromFile (const char * fileName, + UA_ByteString * cert) { + + FILE * fp = fopen(fileName, "rb"); - if(thumbprint->length != UA_SHA1_LENGTH) + if (fp == NULL) return UA_STATUSCODE_BADINTERNALERROR; + + fseek(fp, 0, SEEK_END); + cert->length = (size_t) ftell(fp); + if (UA_ByteString_allocBuffer (cert, cert->length) != UA_STATUSCODE_GOOD) { + fclose (fp); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + fseek(fp, 0, SEEK_SET); + size_t readLen = fread (cert->data, 1, cert->length, fp); + if (readLen != cert->length) { + UA_ByteString_clear (cert); + cert->length = 0; + fclose (fp); + return UA_STATUSCODE_BADINTERNALERROR; + } + fclose (fp); - /* The certificate thumbprint is always a 20 bit sha1 hash, see Part 4 of the Specification. */ -#if MBEDTLS_VERSION_NUMBER >= 0x02070000 - mbedtls_sha1_ret(certificate->data, certificate->length, thumbprint->data); -#else - mbedtls_sha1(certificate->data, certificate->length, thumbprint->data); -#endif return UA_STATUSCODE_GOOD; } -UA_StatusCode -mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context, - mbedtls_ctr_drbg_context *drbgContext, - UA_ByteString *data, const size_t plainTextBlockSize) { - if(data->length % plainTextBlockSize != 0) - return UA_STATUSCODE_BADINTERNALERROR; +static UA_StatusCode +UA_ReloadCertFromFolder (CertContext * ctx) { + UA_StatusCode ret; + struct dirent ** dirlist = NULL; + int i; + int numCertificates; + char certFile[PATH_MAX]; + UA_ByteString strCert; + char folderPath[PATH_MAX]; - size_t max_blocks = data->length / plainTextBlockSize; + UA_ByteString_init (&strCert); - UA_ByteString encrypted; - UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * context->len); - if(retval != UA_STATUSCODE_GOOD) - return retval; + if (ctx->trustListFolder.length > 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list"); - size_t lenDataToEncrypt = data->length; - size_t inOffset = 0; - size_t offset = 0; - const unsigned char *label = NULL; - while(lenDataToEncrypt >= plainTextBlockSize) { - int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random, - drbgContext, MBEDTLS_RSA_PUBLIC, - label, 0, plainTextBlockSize, - data->data + inOffset, encrypted.data + offset); - if(mbedErr) { - UA_ByteString_deleteMembers(&encrypted); - return UA_STATUSCODE_BADINTERNALERROR; + sk_X509_pop_free (ctx->skTrusted, X509_free); + ctx->skTrusted = sk_X509_new_null(); + if (ctx->skTrusted == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; } - inOffset += plainTextBlockSize; - offset += context->len; - lenDataToEncrypt -= plainTextBlockSize; + (void) memcpy (folderPath, ctx->trustListFolder.data, + ctx->trustListFolder.length); + folderPath[ctx->trustListFolder.length] = 0; + numCertificates = scandir(folderPath, &dirlist, + UA_Certificate_Filter_der_pem, + alphasort); + for (i = 0; i < numCertificates; i++) { + if (UA_BuildFullPath (folderPath, dirlist[i]->d_name, + PATH_MAX, certFile) != UA_STATUSCODE_GOOD) { + continue; + } + ret = UA_loadCertFromFile (certFile, &strCert); + if (ret != UA_STATUSCODE_GOOD) { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to load the certificate file %s", certFile); + continue; /* continue or return ? */ + } + if (UA_skTrusted_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to decode the certificate file %s", certFile); + UA_ByteString_clear (&strCert); + continue; /* continue or return ? */ + } + UA_ByteString_clear (&strCert); + } } - memcpy(data->data, encrypted.data, offset); - UA_ByteString_deleteMembers(&encrypted); - return UA_STATUSCODE_GOOD; + if (ctx->issuerListFolder.length > 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list"); + + sk_X509_pop_free (ctx->skIssue, X509_free); + ctx->skIssue = sk_X509_new_null(); + if (ctx->skIssue == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + memcpy (folderPath, ctx->issuerListFolder.data, ctx->issuerListFolder.length); + folderPath[ctx->issuerListFolder.length] = 0; + numCertificates = scandir(folderPath, &dirlist, + UA_Certificate_Filter_der_pem, + alphasort); + for (i = 0; i < numCertificates; i++) { + if (UA_BuildFullPath (folderPath, dirlist[i]->d_name, + PATH_MAX, certFile) != UA_STATUSCODE_GOOD) { + continue; + } + ret = UA_loadCertFromFile (certFile, &strCert); + if (ret != UA_STATUSCODE_GOOD) { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to load the certificate file %s", certFile); + continue; /* continue or return ? */ + } + if (UA_skIssuer_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to decode the certificate file %s", certFile); + UA_ByteString_clear (&strCert); + continue; /* continue or return ? */ + } + UA_ByteString_clear (&strCert); + } + } + + if (ctx->revocationListFolder.length > 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list"); + + sk_X509_CRL_pop_free (ctx->skCrls, X509_CRL_free); + ctx->skCrls = sk_X509_CRL_new_null(); + if (ctx->skCrls == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + memcpy (folderPath, ctx->revocationListFolder.data, ctx->revocationListFolder.length); + folderPath[ctx->revocationListFolder.length] = 0; + numCertificates = scandir(folderPath, &dirlist, + UA_Certificate_Filter_crl, + alphasort); + for (i = 0; i < numCertificates; i++) { + if (UA_BuildFullPath (folderPath, dirlist[i]->d_name, + PATH_MAX, certFile) != UA_STATUSCODE_GOOD) { + continue; + } + ret = UA_loadCertFromFile (certFile, &strCert); + if (ret != UA_STATUSCODE_GOOD) { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to load the revocation file %s", certFile); + continue; /* continue or return ? */ + } + if (UA_skCrls_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) { + UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to decode the revocation file %s", certFile); + UA_ByteString_clear (&strCert); + continue; /* continue or return ? */ + } + UA_ByteString_clear (&strCert); + } + } + + ret = UA_STATUSCODE_GOOD; + return ret; } -UA_StatusCode -mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey, - mbedtls_ctr_drbg_context *drbgContext, - UA_ByteString *data) { - mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey); - mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); +#endif /* end of __linux__ */ - if(data->length % rsaContext->len != 0) +static UA_StatusCode +UA_X509_Store_CTX_Error_To_UAError (int opensslErr) { + UA_StatusCode ret; + + switch (opensslErr) { + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + case X509_V_ERR_CRL_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + ret = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; + break; + case X509_V_ERR_CERT_REVOKED: + ret = UA_STATUSCODE_BADCERTIFICATEREVOKED; + break; + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + break; + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + break; + case X509_V_ERR_UNABLE_TO_GET_CRL: + ret = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; + break; + default: + ret = UA_STATUSCODE_BADCERTIFICATEINVALID; + break; + } + return ret; + } + +static UA_StatusCode +UA_CertificateVerification_Verify (void * verificationContext, + const UA_ByteString * certificate) { + X509_STORE_CTX* storeCtx; + X509_STORE* store; + CertContext * ctx; + UA_StatusCode ret; + int opensslRet; + X509 * certificateX509 = NULL; + + if (verificationContext == NULL) { return UA_STATUSCODE_BADINTERNALERROR; + } + ctx = (CertContext *) verificationContext; + + store = X509_STORE_new(); + storeCtx = X509_STORE_CTX_new(); + + if (store == NULL || storeCtx == NULL) { + ret = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } +#ifdef __linux__ + ret = UA_ReloadCertFromFolder (ctx); + if (ret != UA_STATUSCODE_GOOD) { + goto cleanup; + } +#endif - size_t inOffset = 0; - size_t outOffset = 0; - size_t outLength = 0; - unsigned char buf[512]; + certificateX509 = UA_OpenSSL_LoadCertificate(certificate); + if (certificateX509 == NULL) { + ret = UA_STATUSCODE_BADCERTIFICATEINVALID; + goto cleanup; + } - while(inOffset < data->length) { - int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random, - drbgContext, MBEDTLS_RSA_PRIVATE, - NULL, 0, &outLength, - data->data + inOffset, - buf, 512); - if(mbedErr) - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + X509_STORE_set_flags(store, 0); + opensslRet = X509_STORE_CTX_init (storeCtx, store, certificateX509, + ctx->skIssue); + if (opensslRet != 1) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } - memcpy(data->data + outOffset, buf, outLength); - inOffset += rsaContext->len; - outOffset += outLength; + (void) X509_STORE_CTX_set0_trusted_stack (storeCtx, ctx->skTrusted); + + + /* Set crls to ctx */ + if (sk_X509_CRL_num (ctx->skCrls) > 0) { + X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls); } - data->length = outOffset; + /* Set flag to check if the certificate has an invalid signature */ + X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CHECK_SS_SIGNATURE); + + if (X509_STORE_CTX_get_check_issued(storeCtx) (storeCtx,certificateX509, certificateX509) != 1) { + X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK); + } + + /* This condition will check whether the certificate is a User certificate or a CA certificate. + * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the certificate shall be + * condidered as CA Certificate and cannot be used to establish a connection. Refer the test case + * CTT/Security/Security Certificate Validation/029.js for more details */ + /** \todo Can the ca-parameter of X509_check_purpose can be used? */ + if(X509_check_purpose(certificateX509, X509_PURPOSE_CRL_SIGN, 0) && X509_check_ca(certificateX509)) { + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; + } + + opensslRet = X509_verify_cert (storeCtx); + if (opensslRet == 1) { + ret = UA_STATUSCODE_GOOD; + + /* Check if the not trusted certificate has a CRL file. If there is no CRL file available for the corresponding + * parent certificate then return status code UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN. Refer the test + * case CTT/Security/Security Certificate Validation/002.js */ + if (X509_STORE_CTX_get_check_issued (storeCtx) (storeCtx,certificateX509, certificateX509) != 1) { + /* Free X509_STORE_CTX and reuse it for certification verification */ + if (storeCtx != NULL) { + X509_STORE_CTX_free(storeCtx); + } + + /* Initialised X509_STORE_CTX sructure*/ + storeCtx = X509_STORE_CTX_new(); + + /* Sets up X509_STORE_CTX structure for a subsequent verification operation */ + X509_STORE_set_flags(store, 0); + X509_STORE_CTX_init (storeCtx, store, certificateX509,ctx->skIssue); + + /* Set trust list to ctx */ + (void) X509_STORE_CTX_trusted_stack (storeCtx, ctx->skTrusted); + + /* Set crls to ctx */ + X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls); + + /* Set flags for CRL check */ + X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + + opensslRet = X509_verify_cert (storeCtx); + if (opensslRet != 1) { + opensslRet = X509_STORE_CTX_get_error (storeCtx); + if (opensslRet == X509_V_ERR_UNABLE_TO_GET_CRL) { + ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; + } + } + } + } + else { + opensslRet = X509_STORE_CTX_get_error (storeCtx); + + /* Check the issued certificate of a CA that is not trusted but available */ + if(opensslRet == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN){ + int trusted_cert_len = sk_X509_num(ctx->skTrusted); + int cmpVal; + X509 *trusted_cert; + const ASN1_OCTET_STRING *trusted_cert_keyid; + const ASN1_OCTET_STRING *remote_cert_keyid; + + for (int i = 0; i < trusted_cert_len; i++) { + trusted_cert = sk_X509_value(ctx->skTrusted, i); + + /* Fetch the Subject key identifier of the certificate in trust list */ + trusted_cert_keyid = X509_get0_subject_key_id(trusted_cert); + + /* Fetch the Subject key identifier of the remote certificate */ + remote_cert_keyid = X509_get0_subject_key_id(certificateX509); + + /* Check remote certificate is present in the trust list */ + cmpVal = ASN1_OCTET_STRING_cmp(trusted_cert_keyid, remote_cert_keyid); + if (cmpVal == 0){ + ret = UA_STATUSCODE_GOOD; + goto cleanup; + } + } + } + + /* Return expected OPCUA error code */ + ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet); + } +cleanup: + if (store != NULL) { + X509_STORE_free (store); + } + if (storeCtx != NULL) { + X509_STORE_CTX_free (storeCtx); + } + if (certificateX509 != NULL) { + X509_free (certificateX509); + } + return ret; +} + +static UA_StatusCode +UA_VerifyCertificateAllowAll (void * verificationContext, + const UA_ByteString * certificate) { + (void) verificationContext; + (void) certificate; return UA_STATUSCODE_GOOD; } -int UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target) -{ - UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(key); - int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0); - UA_ByteString_clear(&data); +static UA_StatusCode +UA_CertificateVerification_VerifyApplicationURI (void * verificationContext, + const UA_ByteString * certificate, + const UA_String * applicationURI) { + (void) verificationContext; - return mbedErr; + const unsigned char * pData; + X509 * certificateX509; + UA_String subjectURI; + GENERAL_NAMES * pNames; + int i; + UA_StatusCode ret; + + pData = certificate->data; + if (pData == NULL) { + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + + certificateX509 = UA_OpenSSL_LoadCertificate(certificate); + if (certificateX509 == NULL) { + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + + pNames = (GENERAL_NAMES *) X509_get_ext_d2i(certificateX509, NID_subject_alt_name, + NULL, NULL); + if (pNames == NULL) { + X509_free (certificateX509); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + for (i = 0; i < sk_GENERAL_NAME_num (pNames); i++) { + GENERAL_NAME * value = sk_GENERAL_NAME_value (pNames, i); + if (value->type == GEN_URI) { + subjectURI.length = (size_t) (value->d.ia5->length); + subjectURI.data = (UA_Byte *) UA_malloc (subjectURI.length); + if (subjectURI.data == NULL) { + X509_free (certificateX509); + sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + (void) memcpy (subjectURI.data, value->d.ia5->data, subjectURI.length); + break; + } + + } + + ret = UA_STATUSCODE_GOOD; + if (UA_Bstrstr (subjectURI.data, subjectURI.length, + applicationURI->data, applicationURI->length) == NULL) { + ret = UA_STATUSCODE_BADCERTIFICATEURIINVALID; + } + + X509_free (certificateX509); + sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free); + UA_String_clear (&subjectURI); + return ret; } -UA_StatusCode UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData, UA_ByteString *target) -{ - UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(certData); +/* main entry */ - mbedtls_x509_crt cert; - mbedtls_x509_crt_init(&cert); +UA_StatusCode +UA_CertificateVerification_Trustlist(UA_CertificateVerification * cv, + const UA_ByteString * certificateTrustList, + size_t certificateTrustListSize, + const UA_ByteString * certificateIssuerList, + size_t certificateIssuerListSize, + const UA_ByteString * certificateRevocationList, + size_t certificateRevocationListSize) { + UA_StatusCode ret; - int mbedErr = mbedtls_x509_crt_parse(&cert, data.data, data.length); + if (cv == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } - UA_StatusCode result = UA_STATUSCODE_BADINVALIDARGUMENT; + CertContext * context = (CertContext *) UA_malloc (sizeof (CertContext)); + if (context == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + ret = UA_CertContext_Init (context); + if (ret != UA_STATUSCODE_GOOD) { + return ret; + } - if (!mbedErr) { - UA_ByteString tmp; - tmp.data = cert.raw.p; - tmp.length = cert.raw.len; + cv->verifyApplicationURI = UA_CertificateVerification_VerifyApplicationURI; + cv->clear = UA_CertificateVerification_clear; + cv->context = context; + if (certificateTrustListSize > 0) + cv->verifyCertificate = UA_CertificateVerification_Verify; + else + cv->verifyCertificate = UA_VerifyCertificateAllowAll; + + if (certificateTrustListSize > 0) { + if (UA_skTrusted_Cert2X509 (certificateTrustList, certificateTrustListSize, + context) != UA_STATUSCODE_GOOD) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + } - result = UA_ByteString_copy(&tmp, target); + if (certificateIssuerListSize > 0) { + if (UA_skIssuer_Cert2X509 (certificateIssuerList, certificateIssuerListSize, + context) != UA_STATUSCODE_GOOD) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } } - UA_ByteString_clear(&data); - mbedtls_x509_crt_free(&cert); - return result; + if (certificateRevocationListSize > 0) { + if (UA_skCrls_Cert2X509 (certificateRevocationList, certificateRevocationListSize, + context) != UA_STATUSCODE_GOOD) { + ret = UA_STATUSCODE_BADINTERNALERROR; + goto errout; + } + } + + return UA_STATUSCODE_GOOD; + +errout: + UA_CertificateVerification_clear (cv); + return ret; } -// mbedTLS expects PEM data to be null terminated -// The data length parameter must include the null terminator -UA_ByteString UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data) -{ - UA_ByteString result; - UA_ByteString_init(&result); +#ifdef __linux__ /* Linux only so far */ +UA_StatusCode +UA_CertificateVerification_CertFolders(UA_CertificateVerification * cv, + const char * trustListFolder, + const char * issuerListFolder, + const char * revocationListFolder) { + UA_StatusCode ret; + if (cv == NULL) { + return UA_STATUSCODE_BADINTERNALERROR; + } - if (!data->length) - return result; + CertContext * context = (CertContext *) UA_malloc (sizeof (CertContext)); + if (context == NULL) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + ret = UA_CertContext_Init (context); + if (ret != UA_STATUSCODE_GOOD) { + return ret; + } - if (data->length && data->data[0] == '-') { - UA_ByteString_allocBuffer(&result, data->length + 1); - memcpy(result.data, data->data, data->length); - result.data[data->length] = '\0'; + cv->verifyApplicationURI = UA_CertificateVerification_VerifyApplicationURI; + cv->clear = UA_CertificateVerification_clear; + cv->context = context; + if(trustListFolder == NULL && + issuerListFolder == NULL && + revocationListFolder == NULL) { + cv->verifyCertificate = UA_VerifyCertificateAllowAll; } else { - UA_ByteString_copy(data, &result); + cv->verifyCertificate = UA_CertificateVerification_Verify; } - return result; + /* Only set the folder paths. They will be reloaded during runtime. */ + + context->trustListFolder = UA_STRING_ALLOC(trustListFolder); + context->issuerListFolder = UA_STRING_ALLOC(issuerListFolder); + context->revocationListFolder = UA_STRING_ALLOC(revocationListFolder); + + return UA_STATUSCODE_GOOD; } +#endif + +#endif /* end of defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */ + +/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_mbedtls_common.h" ****/ + +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + + + +#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS) || defined(UA_ENABLE_PUBSUB_ENCRYPTION) + +#include <mbedtls/md.h> +#include <mbedtls/x509_crt.h> +#include <mbedtls/ctr_drbg.h> + +// MBEDTLS_ENTROPY_HARDWARE_ALT should be defined if your hardware does not supportd platform entropy + +#define UA_SHA1_LENGTH 20 + +_UA_BEGIN_DECLS + +void +swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB); + +void +mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key, + const UA_ByteString *in, unsigned char *out); + +UA_StatusCode +mbedtls_generateKey(mbedtls_md_context_t *context, + const UA_ByteString *secret, const UA_ByteString *seed, + UA_ByteString *out); + +UA_StatusCode +mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message, + const UA_ByteString *signature); + +UA_StatusCode +mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey, + mbedtls_ctr_drbg_context *drbgContext, + const UA_ByteString *message, + UA_ByteString *signature); + +UA_StatusCode +mbedtls_thumbprint_sha1(const UA_ByteString *certificate, + UA_ByteString *thumbprint); + +/* Set the hashing scheme before calling + * E.g. mbedtls_rsa_set_padding(context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); */ +UA_StatusCode +mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context, + mbedtls_ctr_drbg_context *drbgContext, + UA_ByteString *data, const size_t plainTextBlockSize); + +UA_StatusCode +mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey, + mbedtls_ctr_drbg_context *drbgContext, + UA_ByteString *data); + +int UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target, void *p_rng); + +UA_StatusCode UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData, UA_ByteString *target); + +UA_ByteString UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data); + +_UA_END_DECLS #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/ua_securitypolicy_basic128rsa15.c" ***********************************/ + +/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_basic128rsa15.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -58795,7 +66827,6 @@ UA_ByteString UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data) #include <mbedtls/aes.h> #include <mbedtls/ctr_drbg.h> #include <mbedtls/entropy.h> -#include <mbedtls/entropy_poll.h> #include <mbedtls/error.h> #include <mbedtls/md.h> #include <mbedtls/sha1.h> @@ -58844,22 +66875,20 @@ typedef struct { /********************/ static UA_StatusCode -asym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - Basic128Rsa15_ChannelContext *cc, +asym_verify_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, const UA_ByteString *message, const UA_ByteString *signature) { - if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + if(message == NULL || signature == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature); } static UA_StatusCode -asym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - Basic128Rsa15_ChannelContext *cc, +asym_sign_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, const UA_ByteString *message, UA_ByteString *signature) { - if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + if(message == NULL || signature == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; Basic128Rsa15_PolicyContext *pc = cc->policyContext; @@ -58868,43 +66897,58 @@ asym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, } static size_t -asym_getLocalSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc) { - if(securityPolicy == NULL || cc == NULL) +asym_getLocalSignatureSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) { + if(cc == NULL) return 0; - +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len; +#else + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey)); +#endif + + } static size_t -asym_getRemoteSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc) { - if(securityPolicy == NULL || cc == NULL) +asym_getRemoteSignatureSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) { + if(cc == NULL) return 0; +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +#else + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif + } static UA_StatusCode -asym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - Basic128Rsa15_ChannelContext *cc, +asym_encrypt_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. - getRemotePlainTextBlockSize(securityPolicy, cc); + mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); + +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + size_t plainTextBlockSize = remoteRsaContext->len - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; +#else + size_t keylen = mbedtls_rsa_get_len(remoteRsaContext); + size_t plainTextBlockSize = mbedtls_rsa_get_len(remoteRsaContext) - + UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; +#endif if(data->length % plainTextBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); - mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V15, 0); - + size_t blocks = data->length / plainTextBlockSize; UA_ByteString encrypted; - const size_t bufferOverhead = - UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(securityPolicy, cc, data->length); - UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, data->length + bufferOverhead); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, blocks * remoteRsaContext->len); +#else + UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, blocks * keylen); +#endif if(retval != UA_STATUSCODE_GOOD) return retval; @@ -58921,7 +66965,7 @@ asym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, mbedtls_ctr_drbg_random, &pc->drbgContext); if(mbedErr) { - UA_ByteString_deleteMembers(&encrypted); + UA_ByteString_clear(&encrypted); return UA_STATUSCODE_BADINTERNALERROR; } @@ -58931,23 +66975,27 @@ asym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, } memcpy(data->data, encrypted.data, offset); - UA_ByteString_deleteMembers(&encrypted); + UA_ByteString_clear(&encrypted); return UA_STATUSCODE_GOOD; } static UA_StatusCode -asym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - Basic128Rsa15_ChannelContext *cc, +asym_decrypt_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->policyContext->localPrivateKey); - mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); - + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 if(data->length % rsaContext->len != 0) + return UA_STATUSCODE_BADINTERNALERROR; +#else + size_t keylen = mbedtls_rsa_get_len(rsaContext); + if(data->length % keylen != 0) return UA_STATUSCODE_BADINTERNALERROR; +#endif size_t inOffset = 0; size_t outOffset = 0; @@ -58955,14 +67003,25 @@ asym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, unsigned char buf[512]; while(inOffset < data->length) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 int mbedErr = mbedtls_pk_decrypt(&cc->policyContext->localPrivateKey, data->data + inOffset, rsaContext->len, buf, &outLength, 512, NULL, NULL); +#else + int mbedErr = mbedtls_pk_decrypt(&cc->policyContext->localPrivateKey, + data->data + inOffset, keylen, + buf, &outLength, 512, NULL, NULL); +#endif + if(mbedErr) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; memcpy(data->data + outOffset, buf, outLength); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 inOffset += rsaContext->len; +#else + inOffset += keylen; +#endif outOffset += outLength; } @@ -58971,29 +67030,45 @@ asym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, } static size_t -asym_getLocalEncryptionKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc) { - return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8; +asym_getLocalEncryptionKeyLength_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif } static size_t -asym_getRemoteEncryptionKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc) { +asym_getRemoteEncryptionKeyLength_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) { return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8; } static size_t -asym_getRemoteBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc) { +asym_getRemoteBlockSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); return rsaContext->len; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif } static size_t -asym_getRemotePlainTextBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc) { +asym_getRemotePlainTextBlockSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); return rsaContext->len - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) - + UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; +#endif } static UA_StatusCode @@ -59023,22 +67098,17 @@ asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15(const UA_Security /*******************/ static UA_StatusCode -sym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - Basic128Rsa15_ChannelContext *cc, +sym_verify_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, const UA_ByteString *message, const UA_ByteString *signature) { - if(securityPolicy == NULL || cc == NULL || message == NULL || signature == NULL) + if(cc == NULL || message == NULL || signature == NULL) return UA_STATUSCODE_BADINTERNALERROR; /* Compute MAC */ - if(signature->length != UA_SHA1_LENGTH) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Signature size does not have the desired size defined by the security policy"); + if(signature->length != UA_SHA1_LENGTH) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - Basic128Rsa15_PolicyContext *pc = - (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; + Basic128Rsa15_PolicyContext *pc = cc->policyContext; unsigned char mac[UA_SHA1_LENGTH]; mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac); @@ -59050,8 +67120,7 @@ sym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, } static UA_StatusCode -sym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc, +sym_sign_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc, const UA_ByteString *message, UA_ByteString *signature) { if(signature->length != UA_SHA1_LENGTH) @@ -59063,55 +67132,42 @@ sym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, } static size_t -sym_getSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { +sym_getSignatureSize_sp_basic128rsa15(const void *channelContext) { return UA_SHA1_LENGTH; } static size_t -sym_getSigningKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getSigningKeyLength_sp_basic128rsa15(const void *const channelContext) { return UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH; } static size_t -sym_getEncryptionKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { +sym_getEncryptionKeyLength_sp_basic128rsa15(const void *channelContext) { return UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH; } static size_t -sym_getEncryptionBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getEncryptionBlockSize_sp_basic128rsa15(const void *const channelContext) { return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE; } static size_t -sym_getPlainTextBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getPlainTextBlockSize_sp_basic128rsa15(const void *const channelContext) { return UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE; } static UA_StatusCode -sym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc, +sym_encrypt_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - if(cc->localSymIv.length != - securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc)) + if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE) return UA_STATUSCODE_BADINTERNALERROR; - size_t plainTextBlockSize = - securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalPlainTextBlockSize(securityPolicy, cc); - - if(data->length % plainTextBlockSize != 0) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Length of data to encrypt is not a multiple of the plain text block size." - "Padding might not have been calculated appropriately."); + size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE; + if(data->length % plainTextBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } /* Keylength in bits */ unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8); @@ -59129,32 +67185,27 @@ sym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, ivCopy.data, data->data, data->data); if(mbedErr) retval = UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&ivCopy); + UA_ByteString_clear(&ivCopy); return retval; } static UA_StatusCode -sym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const Basic128Rsa15_ChannelContext *cc, +sym_decrypt_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - size_t encryptionBlockSize = securityPolicy->symmetricModule.cryptoModule. - encryptionAlgorithm.getRemoteBlockSize(securityPolicy, cc); - + size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE; if(cc->remoteSymIv.length != encryptionBlockSize) return UA_STATUSCODE_BADINTERNALERROR; - if(data->length % encryptionBlockSize != 0) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Length of data to decrypt is not a multiple of the encryptingBlock size."); + if(data->length % encryptionBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8); mbedtls_aes_context aesContext; - int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength); + int mbedErr = mbedtls_aes_setkey_dec(&aesContext, + cc->remoteSymEncryptingKey.data, keylength); if(mbedErr) return UA_STATUSCODE_BADINTERNALERROR; @@ -59167,36 +67218,27 @@ sym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, ivCopy.data, data->data, data->data); if(mbedErr) retval = UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&ivCopy); + UA_ByteString_clear(&ivCopy); return retval; } static UA_StatusCode -sym_generateKey_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *secret, const UA_ByteString *seed, - UA_ByteString *out) { - if(securityPolicy == NULL || secret == NULL || seed == NULL || out == NULL) +sym_generateKey_sp_basic128rsa15(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + if(secret == NULL || seed == NULL || out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - - Basic128Rsa15_PolicyContext *pc = - (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; - + Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)policyContext; return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out); } static UA_StatusCode -sym_generateNonce_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, - UA_ByteString *out) { - if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL) +sym_generateNonce_sp_basic128rsa15(void *policyContext, UA_ByteString *out) { + if(out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - - Basic128Rsa15_PolicyContext *pc = - (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; - + Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)policyContext; int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length); if(mbedErr) return UA_STATUSCODE_BADUNEXPECTEDERROR; - return UA_STATUSCODE_GOOD; } @@ -59218,26 +67260,29 @@ parseRemoteCertificate_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, return UA_STATUSCODE_BADSECURITYCHECKSFAILED; /* Check the key length */ +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); if(rsaContext->len < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH || rsaContext->len > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH) return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; - +#else + size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); + if(keylen < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH || + keylen > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH) + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; +#endif return UA_STATUSCODE_GOOD; } static void channelContext_deleteContext_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc) { - UA_ByteString_deleteMembers(&cc->localSymSigningKey); - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); - UA_ByteString_deleteMembers(&cc->localSymIv); - - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); - UA_ByteString_deleteMembers(&cc->remoteSymIv); - + UA_ByteString_clear(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymIv); + UA_ByteString_clear(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymIv); mbedtls_x509_crt_free(&cc->remoteCertificate); - UA_free(cc); } @@ -59283,7 +67328,7 @@ channelContext_setLocalSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelCo if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); return UA_ByteString_copy(key, &cc->localSymEncryptingKey); } @@ -59293,7 +67338,7 @@ channelContext_setLocalSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelConte if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymSigningKey); return UA_ByteString_copy(key, &cc->localSymSigningKey); } @@ -59304,7 +67349,7 @@ channelContext_setLocalSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymIv); + UA_ByteString_clear(&cc->localSymIv); return UA_ByteString_copy(iv, &cc->localSymIv); } @@ -59314,7 +67359,7 @@ channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelC if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); } @@ -59324,7 +67369,7 @@ channelContext_setRemoteSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelCont if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymSigningKey); return UA_ByteString_copy(key, &cc->remoteSymSigningKey); } @@ -59334,7 +67379,7 @@ channelContext_setRemoteSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymIv); + UA_ByteString_clear(&cc->remoteSymIv); return UA_ByteString_copy(iv, &cc->remoteSymIv); } @@ -59364,7 +67409,7 @@ clear_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) { if(securityPolicy == NULL) return; - UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + UA_ByteString_clear(&securityPolicy->localCertificate); if(securityPolicy->policyContext == NULL) return; @@ -59377,7 +67422,7 @@ clear_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) { mbedtls_entropy_free(&pc->entropyContext); mbedtls_pk_free(&pc->localPrivateKey); mbedtls_md_free(&pc->sha1MdContext); - UA_ByteString_deleteMembers(&pc->localCertThumbprint); + UA_ByteString_clear(&pc->localCertThumbprint); UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, "Deleted members of EndpointContext for sp_basic128rsa15"); @@ -59398,7 +67443,7 @@ updateCertificateAndPrivateKey_sp_basic128rsa15(UA_SecurityPolicy *securityPolic Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; - UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + UA_ByteString_clear(&securityPolicy->localCertificate); UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate); @@ -59408,7 +67453,7 @@ updateCertificateAndPrivateKey_sp_basic128rsa15(UA_SecurityPolicy *securityPolic /* Set the new private key */ mbedtls_pk_free(&pc->localPrivateKey); mbedtls_pk_init(&pc->localPrivateKey); - int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey); + int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext); if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -59466,10 +67511,8 @@ policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy, goto error; } - /* Add the system entropy source */ - mbedErr = mbedtls_entropy_add_source(&pc->entropyContext, - MBEDTLS_ENTROPY_POLL_METHOD, NULL, 0, - MBEDTLS_ENTROPY_SOURCE_STRONG); + mbedErr = mbedtls_entropy_self_test(0); + if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -59486,7 +67529,7 @@ policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy, } /* Set the private key */ - mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey); + mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext); if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; @@ -59536,15 +67579,13 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l asym_signatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); asym_signatureAlgorithm->verify = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic128rsa15; + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic128rsa15; asym_signatureAlgorithm->sign = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic128rsa15; + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic128rsa15; asym_signatureAlgorithm->getLocalSignatureSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic128rsa15; + (size_t (*)(const void *))asym_getLocalSignatureSize_sp_basic128rsa15; asym_signatureAlgorithm->getRemoteSignatureSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic128rsa15; + (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_basic128rsa15; asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function @@ -59552,20 +67593,17 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l &asymmetricModule->cryptoModule.encryptionAlgorithm; asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5"); asym_encryptionAlgorithm->encrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15; + (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15; asym_encryptionAlgorithm->decrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *)) - asym_decrypt_sp_basic128rsa15; + (UA_StatusCode(*)(void *, UA_ByteString *)) asym_decrypt_sp_basic128rsa15; asym_encryptionAlgorithm->getLocalKeyLength = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalEncryptionKeyLength_sp_basic128rsa15; + (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_basic128rsa15; asym_encryptionAlgorithm->getRemoteKeyLength = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength_sp_basic128rsa15; - asym_encryptionAlgorithm->getLocalBlockSize = NULL; // TODO: Write function - asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const UA_SecurityPolicy *, - const void *))asym_getRemoteBlockSize_sp_basic128rsa15; - asym_encryptionAlgorithm->getLocalPlainTextBlockSize = NULL; // TODO: Write function + (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_basic128rsa15; + asym_encryptionAlgorithm->getRemoteBlockSize = + (size_t (*)(const void *))asym_getRemoteBlockSize_sp_basic128rsa15; asym_encryptionAlgorithm->getRemotePlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic128rsa15; + (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_basic128rsa15; asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic128rsa15; asymmetricModule->compareCertificateThumbprint = @@ -59580,37 +67618,30 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l sym_signatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); sym_signatureAlgorithm->verify = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, const UA_ByteString *, + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_basic128rsa15; sym_signatureAlgorithm->sign = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic128rsa15; + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic128rsa15; sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic128rsa15; sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic128rsa15; sym_signatureAlgorithm->getLocalKeyLength = - (size_t (*)(const UA_SecurityPolicy *, - const void *))sym_getSigningKeyLength_sp_basic128rsa15; + (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic128rsa15; sym_signatureAlgorithm->getRemoteKeyLength = - (size_t (*)(const UA_SecurityPolicy *, - const void *))sym_getSigningKeyLength_sp_basic128rsa15; + (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic128rsa15; UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = &symmetricModule->cryptoModule.encryptionAlgorithm; sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc"); sym_encryptionAlgorithm->encrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic128rsa15; + (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_basic128rsa15; sym_encryptionAlgorithm->decrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_decrypt_sp_basic128rsa15; + (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_basic128rsa15; sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15; sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15; - sym_encryptionAlgorithm->getLocalBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic128rsa15; sym_encryptionAlgorithm->getRemoteBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic128rsa15; - sym_encryptionAlgorithm->getLocalPlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic128rsa15; + (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_basic128rsa15; sym_encryptionAlgorithm->getRemotePlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic128rsa15; + (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_basic128rsa15; symmetricModule->secureChannelNonceLength = 16; // Use the same signature algorithm as the asymmetric component for certificate signing (see standard) @@ -59650,7 +67681,7 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/ua_securitypolicy_basic256.c" ***********************************/ +/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_basic256.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -59670,7 +67701,6 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l #include <mbedtls/aes.h> #include <mbedtls/entropy.h> -#include <mbedtls/entropy_poll.h> #include <mbedtls/error.h> #include <mbedtls/sha1.h> #include <mbedtls/version.h> @@ -59719,11 +67749,10 @@ typedef struct { /* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ static UA_StatusCode -asym_verify_sp_basic256(const UA_SecurityPolicy *securityPolicy, - Basic256_ChannelContext *cc, +asym_verify_sp_basic256(Basic256_ChannelContext *cc, const UA_ByteString *message, const UA_ByteString *signature) { - if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + if(message == NULL || signature == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature); @@ -59731,11 +67760,10 @@ asym_verify_sp_basic256(const UA_SecurityPolicy *securityPolicy, /* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ static UA_StatusCode -asym_sign_sp_basic256(const UA_SecurityPolicy *securityPolicy, - Basic256_ChannelContext *cc, +asym_sign_sp_basic256(Basic256_ChannelContext *cc, const UA_ByteString *message, UA_ByteString *signature) { - if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + if(message == NULL || signature == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; Basic256_PolicyContext *pc = cc->policyContext; @@ -59744,31 +67772,49 @@ asym_sign_sp_basic256(const UA_SecurityPolicy *securityPolicy, } static size_t -asym_getLocalSignatureSize_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc) { - if(securityPolicy == NULL || cc == NULL) +asym_getLocalSignatureSize_sp_basic256(const Basic256_ChannelContext *cc) { + if(cc == NULL) return 0; +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len; +#else + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey)); + +#endif } static size_t -asym_getRemoteSignatureSize_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc) { - if(securityPolicy == NULL || cc == NULL) +asym_getRemoteSignatureSize_sp_basic256(const Basic256_ChannelContext *cc) { + if(cc == NULL) return 0; +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +#else + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif +} + +static size_t +asym_getRemotePlainTextBlockSize_sp_basic256(const Basic256_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) - + UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN; +#endif } /* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ static UA_StatusCode -asym_encrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, - Basic256_ChannelContext *cc, +asym_encrypt_sp_basic256(Basic256_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule. - encryptionAlgorithm.getRemotePlainTextBlockSize(securityPolicy, cc); + const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_basic256(cc); mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); @@ -59779,39 +67825,34 @@ asym_encrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, /* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ static UA_StatusCode -asym_decrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, - Basic256_ChannelContext *cc, +asym_decrypt_sp_basic256(Basic256_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey, &cc->policyContext->drbgContext, data); } static size_t -asym_getLocalEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc) { +asym_getLocalEncryptionKeyLength_sp_basic256(const Basic256_ChannelContext *cc) { return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8; } static size_t -asym_getRemoteEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc) { +asym_getRemoteEncryptionKeyLength_sp_basic256(const Basic256_ChannelContext *cc) { return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8; } static size_t -asym_getRemoteBlockSize_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc) { +asym_getRemoteBlockSize_sp_basic256(const Basic256_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); return rsaContext->len; -} - -static size_t -asym_getRemotePlainTextBlockSize_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc) { - mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); - return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif } static UA_StatusCode @@ -59841,22 +67882,17 @@ asymmetricModule_compareCertificateThumbprint_sp_basic256(const UA_SecurityPolic /*******************/ static UA_StatusCode -sym_verify_sp_basic256(const UA_SecurityPolicy *securityPolicy, - Basic256_ChannelContext *cc, +sym_verify_sp_basic256(Basic256_ChannelContext *cc, const UA_ByteString *message, const UA_ByteString *signature) { - if(securityPolicy == NULL || cc == NULL || message == NULL || signature == NULL) + if(cc == NULL || message == NULL || signature == NULL) return UA_STATUSCODE_BADINTERNALERROR; /* Compute MAC */ - if(signature->length != UA_SHA1_LENGTH) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Signature size does not have the desired size defined by the security policy"); + if(signature->length != UA_SHA1_LENGTH) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - Basic256_PolicyContext *pc = - (Basic256_PolicyContext *)securityPolicy->policyContext; + Basic256_PolicyContext *pc = cc->policyContext; unsigned char mac[UA_SHA1_LENGTH]; mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac); @@ -59868,10 +67904,8 @@ sym_verify_sp_basic256(const UA_SecurityPolicy *securityPolicy, } static UA_StatusCode -sym_sign_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc, - const UA_ByteString *message, - UA_ByteString *signature) { +sym_sign_sp_basic256(const Basic256_ChannelContext *cc, + const UA_ByteString *message, UA_ByteString *signature) { if(signature->length != UA_SHA1_LENGTH) return UA_STATUSCODE_BADINTERNALERROR; @@ -59881,57 +67915,42 @@ sym_sign_sp_basic256(const UA_SecurityPolicy *securityPolicy, } static size_t -sym_getSignatureSize_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { +sym_getSignatureSize_sp_basic256(const void *channelContext) { return UA_SHA1_LENGTH; } static size_t -sym_getSigningKeyLength_sp_basic256(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getSigningKeyLength_sp_basic256(const void *const channelContext) { return UA_BASIC256_SYM_SIGNING_KEY_LENGTH; } static size_t -sym_getEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { +sym_getEncryptionKeyLength_sp_basic256(const void *channelContext) { return UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH; } static size_t -sym_getEncryptionBlockSize_sp_basic256(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getEncryptionBlockSize_sp_basic256(const void *const channelContext) { return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE; } static size_t -sym_getPlainTextBlockSize_sp_basic256(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getPlainTextBlockSize_sp_basic256(const void *const channelContext) { return UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE; } static UA_StatusCode -sym_encrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc, - UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) +sym_encrypt_sp_basic256(const Basic256_ChannelContext *cc, + UA_ByteString *data) { + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - if(cc->localSymIv.length != - securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. - getLocalBlockSize(securityPolicy, cc)) + if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE) return UA_STATUSCODE_BADINTERNALERROR; - size_t plainTextBlockSize = - securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. - getLocalPlainTextBlockSize(securityPolicy, cc); - - if(data->length % plainTextBlockSize != 0) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Length of data to encrypt is not a multiple of the plain text block size." - "Padding might not have been calculated appropriately."); + size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE; + if(data->length % plainTextBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } /* Keylength in bits */ unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8); @@ -59949,29 +67968,22 @@ sym_encrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, ivCopy.data, data->data, data->data); if(mbedErr) retval = UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&ivCopy); + UA_ByteString_clear(&ivCopy); return retval; } static UA_StatusCode -sym_decrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const Basic256_ChannelContext *cc, - UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) +sym_decrypt_sp_basic256(const Basic256_ChannelContext *cc, + UA_ByteString *data) { + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - size_t encryptionBlockSize = - securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. - getRemoteBlockSize(securityPolicy, cc); - + size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE; if(cc->remoteSymIv.length != encryptionBlockSize) return UA_STATUSCODE_BADINTERNALERROR; - if(data->length % encryptionBlockSize != 0) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Length of data to decrypt is not a multiple of the encryptingBlock size."); + if(data->length % encryptionBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8); mbedtls_aes_context aesContext; @@ -59988,36 +68000,27 @@ sym_decrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy, ivCopy.data, data->data, data->data); if(mbedErr) retval = UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&ivCopy); + UA_ByteString_clear(&ivCopy); return retval; } static UA_StatusCode -sym_generateKey_sp_basic256(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *secret, const UA_ByteString *seed, - UA_ByteString *out) { - if(securityPolicy == NULL || secret == NULL || seed == NULL || out == NULL) +sym_generateKey_sp_basic256(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + if(secret == NULL || seed == NULL || out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - - Basic256_PolicyContext *pc = - (Basic256_PolicyContext *)securityPolicy->policyContext; - + Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policyContext; return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out); } static UA_StatusCode -sym_generateNonce_sp_basic256(const UA_SecurityPolicy *securityPolicy, - UA_ByteString *out) { - if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL) +sym_generateNonce_sp_basic256(void *policyContext, UA_ByteString *out) { + if(out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - - Basic256_PolicyContext *pc = - (Basic256_PolicyContext *)securityPolicy->policyContext; - + Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policyContext; int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length); if(mbedErr) return UA_STATUSCODE_BADUNEXPECTEDERROR; - return UA_STATUSCODE_GOOD; } @@ -60039,9 +68042,15 @@ parseRemoteCertificate_sp_basic256(Basic256_ChannelContext *cc, return UA_STATUSCODE_BADSECURITYCHECKSFAILED; /* Check the key length */ +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); if(rsaContext->len < UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH || rsaContext->len > UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH) +#else + size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); + if(keylen < UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH || + keylen > UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH) +#endif return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; return UA_STATUSCODE_GOOD; @@ -60049,13 +68058,13 @@ parseRemoteCertificate_sp_basic256(Basic256_ChannelContext *cc, static void channelContext_deleteContext_sp_basic256(Basic256_ChannelContext *cc) { - UA_ByteString_deleteMembers(&cc->localSymSigningKey); - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); - UA_ByteString_deleteMembers(&cc->localSymIv); + UA_ByteString_clear(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymIv); - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); - UA_ByteString_deleteMembers(&cc->remoteSymIv); + UA_ByteString_clear(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymIv); mbedtls_x509_crt_free(&cc->remoteCertificate); @@ -60104,7 +68113,7 @@ channelContext_setLocalSymEncryptingKey_sp_basic256(Basic256_ChannelContext *cc, if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); return UA_ByteString_copy(key, &cc->localSymEncryptingKey); } @@ -60114,7 +68123,7 @@ channelContext_setLocalSymSigningKey_sp_basic256(Basic256_ChannelContext *cc, if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymSigningKey); return UA_ByteString_copy(key, &cc->localSymSigningKey); } @@ -60125,7 +68134,7 @@ channelContext_setLocalSymIv_sp_basic256(Basic256_ChannelContext *cc, if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymIv); + UA_ByteString_clear(&cc->localSymIv); return UA_ByteString_copy(iv, &cc->localSymIv); } @@ -60135,7 +68144,7 @@ channelContext_setRemoteSymEncryptingKey_sp_basic256(Basic256_ChannelContext *cc if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); } @@ -60145,7 +68154,7 @@ channelContext_setRemoteSymSigningKey_sp_basic256(Basic256_ChannelContext *cc, if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymSigningKey); return UA_ByteString_copy(key, &cc->remoteSymSigningKey); } @@ -60155,7 +68164,7 @@ channelContext_setRemoteSymIv_sp_basic256(Basic256_ChannelContext *cc, if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymIv); + UA_ByteString_clear(&cc->remoteSymIv); return UA_ByteString_copy(iv, &cc->remoteSymIv); } @@ -60185,7 +68194,7 @@ clear_sp_basic256(UA_SecurityPolicy *securityPolicy) { if(securityPolicy == NULL) return; - UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + UA_ByteString_clear(&securityPolicy->localCertificate); if(securityPolicy->policyContext == NULL) return; @@ -60198,7 +68207,7 @@ clear_sp_basic256(UA_SecurityPolicy *securityPolicy) { mbedtls_entropy_free(&pc->entropyContext); mbedtls_pk_free(&pc->localPrivateKey); mbedtls_md_free(&pc->sha1MdContext); - UA_ByteString_deleteMembers(&pc->localCertThumbprint); + UA_ByteString_clear(&pc->localCertThumbprint); UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, "Deleted members of EndpointContext for sp_basic256"); @@ -60220,7 +68229,7 @@ updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy, Basic256_PolicyContext *pc = (Basic256_PolicyContext *) securityPolicy->policyContext; - UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + UA_ByteString_clear(&securityPolicy->localCertificate); UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate); @@ -60231,7 +68240,7 @@ updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy, mbedtls_pk_free(&pc->localPrivateKey); mbedtls_pk_init(&pc->localPrivateKey); - int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey); + int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext); if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; @@ -60290,10 +68299,8 @@ policyContext_newContext_sp_basic256(UA_SecurityPolicy *securityPolicy, goto error; } - /* Add the system entropy source */ - mbedErr = mbedtls_entropy_add_source(&pc->entropyContext, - MBEDTLS_ENTROPY_POLL_METHOD, NULL, 0, - MBEDTLS_ENTROPY_SOURCE_STRONG); + mbedErr = mbedtls_entropy_self_test(0); + if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -60310,7 +68317,7 @@ policyContext_newContext_sp_basic256(UA_SecurityPolicy *securityPolicy, } /* Set the private key */ - mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey); + mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext); if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -60359,15 +68366,13 @@ UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localC asym_signatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); asym_signatureAlgorithm->verify = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256; + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256; asym_signatureAlgorithm->sign = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256; + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256; asym_signatureAlgorithm->getLocalSignatureSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic256; + (size_t (*)(const void *))asym_getLocalSignatureSize_sp_basic256; asym_signatureAlgorithm->getRemoteSignatureSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic256; + (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_basic256; asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function @@ -60375,20 +68380,17 @@ UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localC &asymmetricModule->cryptoModule.encryptionAlgorithm; asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); asym_encryptionAlgorithm->encrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic256; + (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_basic256; asym_encryptionAlgorithm->decrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *)) - asym_decrypt_sp_basic256; + (UA_StatusCode(*)(void *, UA_ByteString *))asym_decrypt_sp_basic256; asym_encryptionAlgorithm->getLocalKeyLength = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalEncryptionKeyLength_sp_basic256; + (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_basic256; asym_encryptionAlgorithm->getRemoteKeyLength = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength_sp_basic256; - asym_encryptionAlgorithm->getLocalBlockSize = NULL; // TODO: Write function - asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const UA_SecurityPolicy *, - const void *))asym_getRemoteBlockSize_sp_basic256; - asym_encryptionAlgorithm->getLocalPlainTextBlockSize = NULL; // TODO: Write function + (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_basic256; + asym_encryptionAlgorithm->getRemoteBlockSize = + (size_t (*)(const void *))asym_getRemoteBlockSize_sp_basic256; asym_encryptionAlgorithm->getRemotePlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic256; + (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_basic256; asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256; asymmetricModule->compareCertificateThumbprint = @@ -60403,37 +68405,30 @@ UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localC sym_signatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); sym_signatureAlgorithm->verify = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, const UA_ByteString *, + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_basic256; sym_signatureAlgorithm->sign = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256; + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256; sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic256; sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256; sym_signatureAlgorithm->getLocalKeyLength = - (size_t (*)(const UA_SecurityPolicy *, - const void *))sym_getSigningKeyLength_sp_basic256; + (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256; sym_signatureAlgorithm->getRemoteKeyLength = - (size_t (*)(const UA_SecurityPolicy *, - const void *))sym_getSigningKeyLength_sp_basic256; + (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256; UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = &symmetricModule->cryptoModule.encryptionAlgorithm; sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0"); sym_encryptionAlgorithm->encrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic256; + (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_basic256; sym_encryptionAlgorithm->decrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_decrypt_sp_basic256; + (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_basic256; sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256; sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256; - sym_encryptionAlgorithm->getLocalBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256; sym_encryptionAlgorithm->getRemoteBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256; - sym_encryptionAlgorithm->getLocalPlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256; + (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_basic256; sym_encryptionAlgorithm->getRemotePlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256; + (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_basic256; symmetricModule->secureChannelNonceLength = 32; // Use the same signature algorithm as the asymmetric component for certificate signing (see standard) @@ -60473,7 +68468,7 @@ UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localC #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/ua_securitypolicy_basic256sha256.c" ***********************************/ +/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_basic256sha256.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -60493,7 +68488,6 @@ UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localC #include <mbedtls/aes.h> #include <mbedtls/ctr_drbg.h> #include <mbedtls/entropy.h> -#include <mbedtls/entropy_poll.h> #include <mbedtls/error.h> #include <mbedtls/md.h> #include <mbedtls/sha1.h> @@ -60546,15 +68540,14 @@ typedef struct { /* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ static UA_StatusCode -asym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - Basic256Sha256_ChannelContext *cc, +asym_verify_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, const UA_ByteString *message, const UA_ByteString *signature) { - if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + if(message == NULL || signature == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; unsigned char hash[UA_SHA256_LENGTH]; -#if MBEDTLS_VERSION_NUMBER >= 0x02070000 +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 // TODO check return status mbedtls_sha256_ret(message->data, message->length, hash, 0); #else @@ -60582,15 +68575,14 @@ asym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, /* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ static UA_StatusCode -asym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - Basic256Sha256_ChannelContext *cc, +asym_sign_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, const UA_ByteString *message, UA_ByteString *signature) { - if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + if(message == NULL || signature == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; unsigned char hash[UA_SHA256_LENGTH]; -#if MBEDTLS_VERSION_NUMBER >= 0x02070000 +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 // TODO check return status mbedtls_sha256_ret(message->data, message->length, hash, 0); #else @@ -60608,6 +68600,9 @@ asym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey, MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH, signature->data, +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + signature->length, +#endif &sigLen, mbedtls_ctr_drbg_random, &pc->drbgContext); if(mbedErr) @@ -60616,33 +68611,61 @@ asym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, } static size_t -asym_getLocalSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc) { - if(securityPolicy == NULL || cc == NULL) +asym_getLocalSignatureSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) { + if(cc == NULL) return 0; - +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len; +#else + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey)); +#endif } static size_t -asym_getRemoteSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc) { - if(securityPolicy == NULL || cc == NULL) +asym_getRemoteSignatureSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) { + if(cc == NULL) return 0; - +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +#else + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif +} + +static size_t +asym_getRemoteBlockSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif +} + +static size_t +asym_getRemotePlainTextBlockSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) - + UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN; +#endif } + /* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ static UA_StatusCode -asym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - Basic256Sha256_ChannelContext *cc, +asym_encrypt_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule. - encryptionAlgorithm.getRemotePlainTextBlockSize(securityPolicy, cc); + const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_basic256sha256(cc); mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); @@ -60653,41 +68676,24 @@ asym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, /* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ static UA_StatusCode -asym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - Basic256Sha256_ChannelContext *cc, +asym_decrypt_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey, &cc->policyContext->drbgContext, data); } static size_t -asym_getLocalEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc) { +asym_getLocalEncryptionKeyLength_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) { return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8; } static size_t -asym_getRemoteEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc) { +asym_getRemoteEncryptionKeyLength_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) { return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8; } -static size_t -asym_getRemoteBlockSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc) { - mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); - return rsaContext->len; -} - -static size_t -asym_getRemotePlainTextBlockSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc) { - mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); - return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN; -} - static UA_StatusCode asym_makeThumbprint_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, const UA_ByteString *certificate, @@ -60715,23 +68721,17 @@ asymmetricModule_compareCertificateThumbprint_sp_basic256sha256(const UA_Securit /*******************/ static UA_StatusCode -sym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - Basic256Sha256_ChannelContext *cc, +sym_verify_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, const UA_ByteString *message, const UA_ByteString *signature) { - if(securityPolicy == NULL || cc == NULL || message == NULL || signature == NULL) + if(cc == NULL || message == NULL || signature == NULL) return UA_STATUSCODE_BADINTERNALERROR; /* Compute MAC */ - if(signature->length != UA_SHA256_LENGTH) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Signature size does not have the desired size defined by the security policy"); + if(signature->length != UA_SHA256_LENGTH) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - - Basic256Sha256_PolicyContext *pc = - (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + Basic256Sha256_PolicyContext *pc = cc->policyContext; unsigned char mac[UA_SHA256_LENGTH]; mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac); @@ -60742,8 +68742,7 @@ sym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, } static UA_StatusCode -sym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc, +sym_sign_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc, const UA_ByteString *message, UA_ByteString *signature) { if(signature->length != UA_SHA256_LENGTH) @@ -60755,55 +68754,43 @@ sym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, } static size_t -sym_getSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { +sym_getSignatureSize_sp_basic256sha256(const void *channelContext) { return UA_SHA256_LENGTH; } static size_t -sym_getSigningKeyLength_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getSigningKeyLength_sp_basic256sha256(const void *channelContext) { return UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH; } static size_t -sym_getEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { +sym_getEncryptionKeyLength_sp_basic256sha256(const void *channelContext) { return UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH; } static size_t -sym_getEncryptionBlockSize_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getEncryptionBlockSize_sp_basic256sha256(const void *channelContext) { return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE; } static size_t -sym_getPlainTextBlockSize_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy, - const void *const channelContext) { +sym_getPlainTextBlockSize_sp_basic256sha256(const void *channelContext) { return UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE; } static UA_StatusCode -sym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc, +sym_encrypt_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - if(cc->localSymIv.length != securityPolicy->symmetricModule.cryptoModule. - encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc)) + if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE) return UA_STATUSCODE_BADINTERNALERROR; - size_t plainTextBlockSize = securityPolicy->symmetricModule.cryptoModule. - encryptionAlgorithm.getLocalPlainTextBlockSize(securityPolicy, cc); + size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE; - if(data->length % plainTextBlockSize != 0) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Length of data to encrypt is not a multiple of the plain text block size." - "Padding might not have been calculated appropriately."); + if(data->length % plainTextBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } /* Keylength in bits */ unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8); @@ -60821,28 +68808,22 @@ sym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, ivCopy.data, data->data, data->data); if(mbedErr) retval = UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&ivCopy); + UA_ByteString_clear(&ivCopy); return retval; } static UA_StatusCode -sym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const Basic256Sha256_ChannelContext *cc, +sym_decrypt_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc, UA_ByteString *data) { - if(securityPolicy == NULL || cc == NULL || data == NULL) + if(cc == NULL || data == NULL) return UA_STATUSCODE_BADINTERNALERROR; - size_t encryptionBlockSize = securityPolicy->symmetricModule.cryptoModule. - encryptionAlgorithm.getRemoteBlockSize(securityPolicy, cc); - + size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE; if(cc->remoteSymIv.length != encryptionBlockSize) return UA_STATUSCODE_BADINTERNALERROR; - if(data->length % encryptionBlockSize != 0) { - UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, - "Length of data to decrypt is not a multiple of the encryptingBlock size."); + if(data->length % encryptionBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8); mbedtls_aes_context aesContext; @@ -60859,31 +68840,24 @@ sym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, ivCopy.data, data->data, data->data); if(mbedErr) retval = UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&ivCopy); + UA_ByteString_clear(&ivCopy); return retval; } static UA_StatusCode -sym_generateKey_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - const UA_ByteString *secret, const UA_ByteString *seed, - UA_ByteString *out) { - if(securityPolicy == NULL || secret == NULL || seed == NULL || out == NULL) +sym_generateKey_sp_basic256sha256(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + if(secret == NULL || seed == NULL || out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - - Basic256Sha256_PolicyContext *pc = - (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; - + Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)policyContext; return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out); } static UA_StatusCode -sym_generateNonce_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, - UA_ByteString *out) { - if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL) +sym_generateNonce_sp_basic256sha256(void *policyContext, UA_ByteString *out) { + if(out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - - Basic256Sha256_PolicyContext *pc = - (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)policyContext; int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length); if(mbedErr) return UA_STATUSCODE_BADUNEXPECTEDERROR; @@ -60908,9 +68882,15 @@ parseRemoteCertificate_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, return UA_STATUSCODE_BADSECURITYCHECKSFAILED; /* Check the key length */ +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); if(rsaContext->len < UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH || rsaContext->len > UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH) +#else + size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); + if(keylen < UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH || + keylen > UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH) +#endif return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; return UA_STATUSCODE_GOOD; @@ -60918,13 +68898,13 @@ parseRemoteCertificate_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, static void channelContext_deleteContext_sp_basic256sha256(Basic256Sha256_ChannelContext *cc) { - UA_ByteString_deleteMembers(&cc->localSymSigningKey); - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); - UA_ByteString_deleteMembers(&cc->localSymIv); + UA_ByteString_clear(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymIv); - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); - UA_ByteString_deleteMembers(&cc->remoteSymIv); + UA_ByteString_clear(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymIv); mbedtls_x509_crt_free(&cc->remoteCertificate); @@ -60973,7 +68953,7 @@ channelContext_setLocalSymEncryptingKey_sp_basic256sha256(Basic256Sha256_Channel if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); return UA_ByteString_copy(key, &cc->localSymEncryptingKey); } @@ -60983,7 +68963,7 @@ channelContext_setLocalSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelCon if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymSigningKey); return UA_ByteString_copy(key, &cc->localSymSigningKey); } @@ -60994,7 +68974,7 @@ channelContext_setLocalSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->localSymIv); + UA_ByteString_clear(&cc->localSymIv); return UA_ByteString_copy(iv, &cc->localSymIv); } @@ -61004,7 +68984,7 @@ channelContext_setRemoteSymEncryptingKey_sp_basic256sha256(Basic256Sha256_Channe if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); } @@ -61014,7 +68994,7 @@ channelContext_setRemoteSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelCo if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymSigningKey); return UA_ByteString_copy(key, &cc->remoteSymSigningKey); } @@ -61024,7 +69004,7 @@ channelContext_setRemoteSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *c if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString_deleteMembers(&cc->remoteSymIv); + UA_ByteString_clear(&cc->remoteSymIv); return UA_ByteString_copy(iv, &cc->remoteSymIv); } @@ -61054,7 +69034,7 @@ clear_sp_basic256sha256(UA_SecurityPolicy *securityPolicy) { if(securityPolicy == NULL) return; - UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + UA_ByteString_clear(&securityPolicy->localCertificate); if(securityPolicy->policyContext == NULL) return; @@ -61067,7 +69047,7 @@ clear_sp_basic256sha256(UA_SecurityPolicy *securityPolicy) { mbedtls_entropy_free(&pc->entropyContext); mbedtls_pk_free(&pc->localPrivateKey); mbedtls_md_free(&pc->sha256MdContext); - UA_ByteString_deleteMembers(&pc->localCertThumbprint); + UA_ByteString_clear(&pc->localCertThumbprint); UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, "Deleted members of EndpointContext for sp_basic256sha256"); @@ -61089,7 +69069,7 @@ updateCertificateAndPrivateKey_sp_basic256sha256(UA_SecurityPolicy *securityPoli Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *) securityPolicy->policyContext; - UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + UA_ByteString_clear(&securityPolicy->localCertificate); UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate); @@ -61099,7 +69079,7 @@ updateCertificateAndPrivateKey_sp_basic256sha256(UA_SecurityPolicy *securityPoli /* Set the new private key */ mbedtls_pk_free(&pc->localPrivateKey); mbedtls_pk_init(&pc->localPrivateKey); - int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey); + int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext); if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -61157,10 +69137,8 @@ policyContext_newContext_sp_basic256sha256(UA_SecurityPolicy *securityPolicy, goto error; } - /* Add the system entropy source */ - mbedErr = mbedtls_entropy_add_source(&pc->entropyContext, - MBEDTLS_ENTROPY_POLL_METHOD, NULL, 0, - MBEDTLS_ENTROPY_SOURCE_STRONG); + mbedErr = mbedtls_entropy_self_test(0); + if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -61177,7 +69155,7 @@ policyContext_newContext_sp_basic256sha256(UA_SecurityPolicy *securityPolicy, } /* Set the private key */ - mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey); + mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext); if(mbedErr) { retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; goto error; @@ -61226,15 +69204,13 @@ UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, const UA_ByteString asym_signatureAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0"); asym_signatureAlgorithm->verify = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256sha256; + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256sha256; asym_signatureAlgorithm->sign = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256sha256; + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256sha256; asym_signatureAlgorithm->getLocalSignatureSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic256sha256; + (size_t (*)(const void *))asym_getLocalSignatureSize_sp_basic256sha256; asym_signatureAlgorithm->getRemoteSignatureSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic256sha256; + (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_basic256sha256; asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function @@ -61242,20 +69218,18 @@ UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, const UA_ByteString &asymmetricModule->cryptoModule.encryptionAlgorithm; asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); asym_encryptionAlgorithm->encrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic256sha256; + (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_basic256sha256; asym_encryptionAlgorithm->decrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *)) + (UA_StatusCode(*)(void *, UA_ByteString *)) asym_decrypt_sp_basic256sha256; asym_encryptionAlgorithm->getLocalKeyLength = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalEncryptionKeyLength_sp_basic256sha256; + (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_basic256sha256; asym_encryptionAlgorithm->getRemoteKeyLength = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength_sp_basic256sha256; - asym_encryptionAlgorithm->getLocalBlockSize = NULL; // TODO: Write function - asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const UA_SecurityPolicy *, - const void *))asym_getRemoteBlockSize_sp_basic256sha256; - asym_encryptionAlgorithm->getLocalPlainTextBlockSize = NULL; // TODO: Write function + (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_basic256sha256; + asym_encryptionAlgorithm->getRemoteBlockSize = + (size_t (*)(const void *))asym_getRemoteBlockSize_sp_basic256sha256; asym_encryptionAlgorithm->getRemotePlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic256sha256; + (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_basic256sha256; asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256sha256; asymmetricModule->compareCertificateThumbprint = @@ -61270,37 +69244,29 @@ UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, const UA_ByteString sym_signatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); sym_signatureAlgorithm->verify = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, const UA_ByteString *, - const UA_ByteString *))sym_verify_sp_basic256sha256; + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_basic256sha256; sym_signatureAlgorithm->sign = - (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, - const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256sha256; + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256sha256; sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic256sha256; sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256sha256; sym_signatureAlgorithm->getLocalKeyLength = - (size_t (*)(const UA_SecurityPolicy *, - const void *))sym_getSigningKeyLength_sp_basic256sha256; + (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256sha256; sym_signatureAlgorithm->getRemoteKeyLength = - (size_t (*)(const UA_SecurityPolicy *, - const void *))sym_getSigningKeyLength_sp_basic256sha256; + (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256sha256; UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = &symmetricModule->cryptoModule.encryptionAlgorithm; - sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc"); + sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc"); sym_encryptionAlgorithm->encrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic256sha256; + (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_basic256sha256; sym_encryptionAlgorithm->decrypt = - (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_decrypt_sp_basic256sha256; + (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_basic256sha256; sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256sha256; sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256sha256; - sym_encryptionAlgorithm->getLocalBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256sha256; sym_encryptionAlgorithm->getRemoteBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256sha256; - sym_encryptionAlgorithm->getLocalPlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256sha256; + (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_basic256sha256; sym_encryptionAlgorithm->getRemotePlainTextBlockSize = - (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256sha256; + (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_basic256sha256; symmetricModule->secureChannelNonceLength = 32; // Use the same signature algorithm as the asymmetric component for certificate signing (see standard) @@ -61340,3732 +69306,4409 @@ UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, const UA_ByteString #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/openssl/securitypolicy_openssl_common.h" ***********************************/ +/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_aes128sha256rsaoaep.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * + * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG + * Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green) * Copyright 2020 (c) Wind River Systems, Inc. - * Copyright 2020 (c) basysKom GmbH - * */ +#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS -#ifdef UA_ENABLE_ENCRYPTION_OPENSSL - -#include <openssl/x509.h> -#include <openssl/evp.h> - -_UA_BEGIN_DECLS -void saveDataToFile(const char *fileName, const UA_ByteString *str); -void UA_Openssl_Init(void); +#include <mbedtls/aes.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/entropy.h> +#include <mbedtls/error.h> +#include <mbedtls/md.h> +#include <mbedtls/sha1.h> +#include <mbedtls/sha256.h> +#include <mbedtls/version.h> +#include <mbedtls/x509_crt.h> -UA_StatusCode -UA_copyCertificate(UA_ByteString *dst, const UA_ByteString *src); +/* Notes: + * mbedTLS' AES allows in-place encryption and decryption. So we don't have to + * allocate temp buffers. + * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer + */ -UA_StatusCode -UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(const UA_ByteString *msg, - X509 *publicKeyX509, - const UA_ByteString *signature); -UA_StatusCode -UA_Openssl_X509_GetCertificateThumbprint(const UA_ByteString *certficate, - UA_ByteString *pThumbprint, - bool bThumbPrint); -UA_StatusCode -UA_Openssl_RSA_Oaep_Decrypt(UA_ByteString *data, - EVP_PKEY *privateKey); -UA_StatusCode -UA_Openssl_RSA_OAEP_Encrypt(UA_ByteString *data, /* The data that is encrypted. - The encrypted data will overwrite - the data that was supplied. */ - size_t paddingSize, X509 *publicX509); +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN 42 +#define UA_SHA1_LENGTH 20 +#define UA_SHA256_LENGTH 32 +#define UA_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH 32 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_KEY_LENGTH 16 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE 16 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH 256 +#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH 512 -UA_StatusCode -UA_Openssl_Random_Key_PSHA256_Derive(const UA_ByteString *secret, - const UA_ByteString *seed, - UA_ByteString *out); +typedef struct { + UA_ByteString localCertThumbprint; -UA_StatusCode -UA_Openssl_RSA_Public_GetKeyLength(X509 *publicKeyX509, UA_Int32 *keyLen); + mbedtls_ctr_drbg_context drbgContext; + mbedtls_entropy_context entropyContext; + mbedtls_md_context_t sha256MdContext; + mbedtls_pk_context localPrivateKey; +} Aes128Sha256PsaOaep_PolicyContext; -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(const UA_ByteString *data, - EVP_PKEY *privateKey, - UA_ByteString *outSignature); +typedef struct { + Aes128Sha256PsaOaep_PolicyContext *policyContext; -UA_StatusCode -UA_OpenSSL_HMAC_SHA256_Verify(const UA_ByteString *message, - const UA_ByteString *key, - const UA_ByteString *signature); + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; -UA_StatusCode -UA_OpenSSL_HMAC_SHA256_Sign(const UA_ByteString *message, - const UA_ByteString *key, - UA_ByteString *signature); + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; -UA_StatusCode -UA_OpenSSL_AES_256_CBC_Decrypt(const UA_ByteString *iv, - const UA_ByteString *key, - UA_ByteString *data /* [in/out]*/); + mbedtls_x509_crt remoteCertificate; +} Aes128Sha256PsaOaep_ChannelContext; -UA_StatusCode -UA_OpenSSL_AES_256_CBC_Encrypt(const UA_ByteString *iv, - const UA_ByteString *key, - UA_ByteString *data /* [in/out]*/); +/********************/ +/* AsymmetricModule */ +/********************/ -UA_StatusCode -UA_OpenSSL_X509_compare(const UA_ByteString *cert, const X509 *b); +/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ +static UA_StatusCode +asym_verify_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(message == NULL || signature == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -UA_StatusCode -UA_Openssl_RSA_Private_GetKeyLength(EVP_PKEY *privateKey, - UA_Int32 *keyLen) ; + unsigned char hash[UA_SHA256_LENGTH]; +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + // TODO check return status + mbedtls_sha256_ret(message->data, message->length, hash, 0); +#else + mbedtls_sha256(message->data, message->length, hash, 0); +#endif -UA_StatusCode -UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(const UA_ByteString *msg, - X509 *publicKeyX509, - const UA_ByteString *signature); + /* Set the RSA settings */ + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256); -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(const UA_ByteString *message, - EVP_PKEY *privateKey, - UA_ByteString *outSignature); -UA_StatusCode -UA_Openssl_Random_Key_PSHA1_Derive(const UA_ByteString *secret, - const UA_ByteString *seed, - UA_ByteString *out); -UA_StatusCode -UA_OpenSSL_HMAC_SHA1_Verify(const UA_ByteString *message, - const UA_ByteString *key, - const UA_ByteString *signature); + /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */ + /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */ + /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL, + MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, + UA_SHA256_LENGTH, hash, + signature->data); */ + int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk, + MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH, + signature->data, signature->length); -UA_StatusCode -UA_OpenSSL_HMAC_SHA1_Sign(const UA_ByteString *message, - const UA_ByteString *key, - UA_ByteString *signature); + if(mbedErr) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + return UA_STATUSCODE_GOOD; +} -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_Decrypt(UA_ByteString *data, - EVP_PKEY *privateKey); +/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ +static UA_StatusCode +asym_sign_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *message, + UA_ByteString *signature) { + if(message == NULL || signature == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_Encrypt(UA_ByteString *data, - size_t paddingSize, - X509 *publicX509); + unsigned char hash[UA_SHA256_LENGTH]; +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + // TODO check return status + mbedtls_sha256_ret(message->data, message->length, hash, 0); +#else + mbedtls_sha256(message->data, message->length, hash, 0); +#endif -UA_StatusCode -UA_OpenSSL_AES_128_CBC_Decrypt(const UA_ByteString *iv, - const UA_ByteString *key, - UA_ByteString *data /* [in/out]*/); + Aes128Sha256PsaOaep_PolicyContext *pc = cc->policyContext; + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey); + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256); -UA_StatusCode -UA_OpenSSL_AES_128_CBC_Encrypt(const UA_ByteString *iv, - const UA_ByteString *key, - UA_ByteString *data /* [in/out]*/); + size_t sigLen = 0; -EVP_PKEY * -UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey); + /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */ + /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */ + int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey, + MBEDTLS_MD_SHA256, hash, + UA_SHA256_LENGTH, signature->data, +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + signature->length, +#endif + &sigLen, mbedtls_ctr_drbg_random, + &pc->drbgContext); + if(mbedErr) + return UA_STATUSCODE_BADINTERNALERROR; + return UA_STATUSCODE_GOOD; +} -X509 * -UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate); +static size_t +asym_getLocalSignatureSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey)); +#endif -X509 * -UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate); +} -X509 * -UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate); +static size_t +asym_getRemoteSignatureSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif +} -UA_StatusCode -UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString *target); +static size_t +asym_getRemoteBlockSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); +#endif +} -_UA_END_DECLS +static size_t +asym_getRemotePlainTextBlockSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len - UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN; +#else + if(cc == NULL) + return 0; + return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) - + UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN; +#endif +} -#endif /* UA_ENABLE_ENCRYPTION_OPENSSL */ +/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ +static UA_StatusCode +asym_encrypt_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + UA_ByteString *data) { + if(cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/openssl/securitypolicy_openssl_common.c" ***********************************/ + const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_aes128sha256rsaoaep(cc); -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2020 (c) Wind River Systems, Inc. - * Copyright 2020 (c) basysKom GmbH - */ + mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); -/* -modification history --------------------- -01feb20,lan written -*/ + return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext, + data, plainTextBlockSize); +} +/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ +static UA_StatusCode +asym_decrypt_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + UA_ByteString *data) { + if(cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey, + &cc->policyContext->drbgContext, data); +} -#ifdef UA_ENABLE_ENCRYPTION_OPENSSL +static size_t +asym_getLocalEncryptionKeyLength_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) { + return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8; +} -#include <openssl/rsa.h> -#include <openssl/evp.h> -#include <openssl/err.h> -#include <openssl/sha.h> -#include <openssl/x509.h> -#include <openssl/hmac.h> -#include <openssl/aes.h> -#include <openssl/pem.h> +static size_t +asym_getRemoteEncryptionKeyLength_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) { + return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8; +} +static UA_StatusCode +asym_makeThumbprint_sp_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificate, + UA_ByteString *thumbprint) { + if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + return mbedtls_thumbprint_sha1(certificate, thumbprint); +} -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL -#define get_pkey_rsa(evp) EVP_PKEY_get0_RSA(evp) -#else -#define get_pkey_rsa(evp) ((evp)->pkey.rsa) -#endif +static UA_StatusCode +asymmetricModule_compareCertificateThumbprint_sp_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) { + if(securityPolicy == NULL || certificateThumbprint == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -#define SHA1_DIGEST_LENGTH 20 /* 160 bits */ + Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) + return UA_STATUSCODE_BADCERTIFICATEINVALID; -/** P_SHA256 Context */ -typedef struct UA_Openssl_P_SHA256_Ctx_ { - size_t seedLen; - size_t secretLen; - UA_Byte A[32]; /* 32 bytes of SHA256 output */ - /* - char seed[seedLen]; - char secret[secretLen]; */ -} UA_Openssl_P_SHA256_Ctx; + return UA_STATUSCODE_GOOD; +} -#define UA_Openssl_P_SHA256_SEED(ctx) ((ctx)->A+32) -#define UA_Openssl_P_SHA256_SECRET(ctx) ((ctx)->A+32+(ctx)->seedLen) +/*******************/ +/* SymmetricModule */ +/*******************/ -/** P_SHA1 Context */ -typedef struct UA_Openssl_P_SHA1_Ctx_ { - size_t seedLen; - size_t secretLen; - UA_Byte A[SHA1_DIGEST_LENGTH]; /* 20 bytes of SHA1 output */ - /* - char seed[seedLen]; - char secret[secretLen]; */ -} UA_Openssl_P_SHA1_Ctx; +static UA_StatusCode +sym_verify_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(cc == NULL || message == NULL || signature == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -#define UA_Openssl_P_SHA1_SEED(ctx) ((ctx)->A + SHA1_DIGEST_LENGTH) -#define UA_Openssl_P_SHA1_SECRET(ctx) ((ctx)->A + SHA1_DIGEST_LENGTH +(ctx)->seedLen) + /* Compute MAC */ + if(signature->length != UA_SHA256_LENGTH) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + Aes128Sha256PsaOaep_PolicyContext *pc = cc->policyContext; + unsigned char mac[UA_SHA256_LENGTH]; + mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac); -void -UA_Openssl_Init (void) { -/* VxWorks7 has initialized the openssl. */ -#ifndef __VXWORKS__ - static UA_Int16 bInit = 0; - if (bInit == 1) - return; - OpenSSL_add_all_algorithms (); - ERR_load_crypto_strings (); - bInit = 1; -#endif + /* Compare with Signature */ + if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH)) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + return UA_STATUSCODE_GOOD; } -/* UA_copyCertificate - allocalte the buffer, copy the certificate and - * add a NULL to the end - */ - -UA_StatusCode -UA_copyCertificate (UA_ByteString * dst, - const UA_ByteString * src) { - UA_StatusCode retval = UA_ByteString_allocBuffer (dst, src->length + 1); - if (retval != UA_STATUSCODE_GOOD) - return retval; - (void) memcpy (dst->data, src->data, src->length); - dst->data[dst->length - 1] = '\0'; - dst->length--; +static UA_StatusCode +sym_sign_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *message, + UA_ByteString *signature) { + if(signature->length != UA_SHA256_LENGTH) + return UA_STATUSCODE_BADINTERNALERROR; - return UA_STATUSCODE_GOOD; + mbedtls_hmac(&cc->policyContext->sha256MdContext, &cc->localSymSigningKey, + message, signature->data); + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_OpenSSL_RSA_Public_Verify (const UA_ByteString * message, - const EVP_MD * evpMd, - X509 * publicKeyX509, - UA_Int16 padding, - const UA_ByteString * signature - ) { - EVP_MD_CTX * mdctx = NULL; - int opensslRet; - EVP_PKEY_CTX * evpKeyCtx; - EVP_PKEY * evpPublicKey = NULL; - UA_StatusCode ret; +static size_t +sym_getSignatureSize_sp_aes128sha256rsaoaep(const void *channelContext) { + return UA_SHA256_LENGTH; +} - mdctx = EVP_MD_CTX_create (); - if (mdctx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } - evpPublicKey = X509_get_pubkey (publicKeyX509); - if (evpPublicKey == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } +static size_t +sym_getSigningKeyLength_sp_aes128sha256rsaoaep(const void *channelContext) { + return UA_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH; +} - opensslRet = EVP_DigestVerifyInit (mdctx, &evpKeyCtx, evpMd, NULL, - evpPublicKey); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - EVP_PKEY_CTX_set_rsa_padding (evpKeyCtx, padding); - opensslRet = EVP_DigestVerifyUpdate (mdctx, message->data, message->length); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - opensslRet = EVP_DigestVerifyFinal(mdctx, signature->data, signature->length); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } +static size_t +sym_getEncryptionKeyLength_sp_aes128sha256rsaoaep(const void *channelContext) { + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_KEY_LENGTH; +} - ret = UA_STATUSCODE_GOOD; -errout: - if (evpPublicKey != NULL) { - EVP_PKEY_free (evpPublicKey); - } - if (mdctx != NULL) { - EVP_MD_CTX_destroy (mdctx); - } - return ret; +static size_t +sym_getEncryptionBlockSize_sp_aes128sha256rsaoaep(const void *channelContext) { + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE; } -UA_StatusCode -UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify (const UA_ByteString * msg, - X509 * publicKeyX509, - const UA_ByteString * signature - ) { - return UA_OpenSSL_RSA_Public_Verify (msg, EVP_sha256(), publicKeyX509, - NID_sha256, signature); +static size_t +sym_getPlainTextBlockSize_sp_aes128sha256rsaoaep(const void *channelContext) { + return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE; } -/* Get certificate thumbprint, and allocate the buffer. - * - */ +static UA_StatusCode +sym_encrypt_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc, + UA_ByteString *data) { + if(cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -UA_StatusCode -UA_Openssl_X509_GetCertificateThumbprint (const UA_ByteString * certficate, - UA_ByteString * pThumbprint, - bool bThumbPrint) { - if (bThumbPrint) { - pThumbprint->length = SHA_DIGEST_LENGTH; - UA_StatusCode ret = UA_ByteString_allocBuffer (pThumbprint, pThumbprint->length); - if (ret != UA_STATUSCODE_GOOD) { - return ret; - } - } - else { - if (pThumbprint->length != SHA_DIGEST_LENGTH) { - return UA_STATUSCODE_BADINTERNALERROR; - } - } - X509 * x509Certificate = UA_OpenSSL_LoadCertificate(certficate); + if(cc->localSymIv.length != UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE) + return UA_STATUSCODE_BADINTERNALERROR; - if (x509Certificate == NULL) { - if (bThumbPrint) { - UA_ByteString_deleteMembers (pThumbprint); - } + size_t plainTextBlockSize = UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE; + + if(data->length % plainTextBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; - } - if (X509_digest (x509Certificate, EVP_sha1(), pThumbprint->data, NULL) - != 1) { - if (bThumbPrint) { - UA_ByteString_deleteMembers (pThumbprint); - } - return UA_STATUSCODE_BADINTERNALERROR; - } - X509_free(x509Certificate); + /* Keylength in bits */ + unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8); + mbedtls_aes_context aesContext; + int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength); + if(mbedErr) + return UA_STATUSCODE_BADINTERNALERROR; - return UA_STATUSCODE_GOOD; + UA_ByteString ivCopy; + UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length, + ivCopy.data, data->data, data->data); + if(mbedErr) + retval = UA_STATUSCODE_BADINTERNALERROR; + UA_ByteString_clear(&ivCopy); + return retval; } static UA_StatusCode -UA_Openssl_RSA_Private_Decrypt (UA_ByteString * data, - EVP_PKEY * privateKey, - UA_Int16 padding) { - if (data == NULL || privateKey == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +sym_decrypt_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc, + UA_ByteString *data) { + if(cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - if (privateKey == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } - - UA_Int32 keySize = RSA_size(get_pkey_rsa(privateKey)); - size_t cipherOffset = 0; - size_t outOffset = 0; - unsigned char buf[2048]; - UA_Int32 decryptedBytes; + size_t encryptionBlockSize = UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE; - while (cipherOffset < data->length) { - decryptedBytes = RSA_private_decrypt (keySize, - data->data + cipherOffset, /* what to decrypt */ - buf, /* where to decrypt */ - get_pkey_rsa(privateKey), /* private key */ - padding - ); - if (decryptedBytes < 0) { - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - memcpy(data->data + outOffset, buf, (size_t) decryptedBytes); - cipherOffset += (size_t) keySize; - outOffset += (size_t) decryptedBytes; - } - data->length = outOffset; - return UA_STATUSCODE_GOOD; -} + if(cc->remoteSymIv.length != encryptionBlockSize) + return UA_STATUSCODE_BADINTERNALERROR; -UA_StatusCode -UA_Openssl_RSA_Oaep_Decrypt (UA_ByteString * data, - EVP_PKEY * privateKey) { - return UA_Openssl_RSA_Private_Decrypt (data, privateKey, - RSA_PKCS1_OAEP_PADDING); + if(data->length % encryptionBlockSize != 0) + return UA_STATUSCODE_BADINTERNALERROR; + + unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8); + mbedtls_aes_context aesContext; + int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength); + if(mbedErr) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString ivCopy; + UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length, + ivCopy.data, data->data, data->data); + if(mbedErr) + retval = UA_STATUSCODE_BADINTERNALERROR; + UA_ByteString_clear(&ivCopy); + return retval; } static UA_StatusCode -UA_Openssl_RSA_Public_Encrypt (const UA_ByteString * message, - X509 * publicX509, - UA_Int16 padding, - size_t paddingSize, - UA_ByteString * encrypted) { - EVP_PKEY_CTX * ctx = NULL; - EVP_PKEY * evpPublicKey = NULL; - int opensslRet; - UA_StatusCode ret; +sym_generateKey_sp_aes128sha256rsaoaep(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + if(secret == NULL || seed == NULL || out == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)policyContext; + return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out); +} - evpPublicKey = X509_get_pubkey (publicX509); - if (evpPublicKey == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } - ctx = EVP_PKEY_CTX_new (evpPublicKey, NULL); - if (ctx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } - opensslRet = EVP_PKEY_encrypt_init (ctx); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - opensslRet = EVP_PKEY_CTX_set_rsa_padding (ctx, padding); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - - /* get the encrypted block size */ - size_t encryptedBlockSize; - RSA * rsa = get_pkey_rsa (evpPublicKey); - size_t keySize = (size_t) RSA_size (rsa); - if (keySize == 0) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - - switch (padding) { - case RSA_PKCS1_OAEP_PADDING: - case RSA_PKCS1_PADDING: - if (keySize <= paddingSize) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - encryptedBlockSize = keySize - paddingSize; - break; - default: - ret = UA_STATUSCODE_BADNOTSUPPORTED; - goto errout; - break; - } +static UA_StatusCode +sym_generateNonce_sp_aes128sha256rsaoaep(void *policyContext, UA_ByteString *out) { + if(out == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + Aes128Sha256PsaOaep_PolicyContext *pc = + (Aes128Sha256PsaOaep_PolicyContext *)policyContext; + int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length); + if(mbedErr) + return UA_STATUSCODE_BADUNEXPECTEDERROR; + return UA_STATUSCODE_GOOD; +} - /* encrypt in reverse order so that [data] may alias [encrypted] */ +/*****************/ +/* ChannelModule */ +/*****************/ - size_t dataPos = message->length; - size_t encryptedPos = ((dataPos - 1) / encryptedBlockSize + 1) * keySize; - size_t bytesToEncrypt = (dataPos - 1) % encryptedBlockSize + 1; - size_t encryptedTextLen = encryptedPos; +/* Assumes that the certificate has been verified externally */ +static UA_StatusCode +parseRemoteCertificate_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *remoteCertificate) { + if(remoteCertificate == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - while (dataPos > 0) { - size_t outlen = keySize; - encryptedPos -= keySize; - dataPos -= bytesToEncrypt; - opensslRet = EVP_PKEY_encrypt (ctx, encrypted->data + encryptedPos, &outlen, - message->data + dataPos, bytesToEncrypt); - - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - bytesToEncrypt = encryptedBlockSize; - } - encrypted->length = encryptedTextLen; + /* Parse the certificate */ + int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data, + remoteCertificate->length); + if(mbedErr) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - ret = UA_STATUSCODE_GOOD; -errout: - if (evpPublicKey != NULL) { - EVP_PKEY_free (evpPublicKey); - } - if (ctx != NULL) { - EVP_PKEY_CTX_free (ctx); - } - return ret; -} + /* Check the key length */ +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + if(rsaContext->len < UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH || + rsaContext->len > UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH) +#else + size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)); + if(keylen < UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH || + keylen > UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH) +#endif + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; -UA_StatusCode -UA_Openssl_RSA_OAEP_Encrypt (UA_ByteString * data, - size_t paddingSize, - X509 * publicX509) { - UA_ByteString message; - UA_StatusCode ret; - - ret = UA_ByteString_copy (data, &message); - if (ret != UA_STATUSCODE_GOOD) { - return ret; - } - ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509, - RSA_PKCS1_OAEP_PADDING, - paddingSize, - data); - UA_ByteString_deleteMembers (&message); - return ret; + return UA_STATUSCODE_GOOD; } -static UA_Openssl_P_SHA256_Ctx * -P_SHA256_Ctx_Create (const UA_ByteString * secret, - const UA_ByteString * seed) { - size_t size = (UA_Int32)sizeof (UA_Openssl_P_SHA256_Ctx) + secret->length + - seed->length; - UA_Openssl_P_SHA256_Ctx * ctx = (UA_Openssl_P_SHA256_Ctx *) UA_malloc (size); - if (ctx == NULL) { - return NULL; - } - ctx->secretLen = secret->length; - ctx->seedLen = seed->length; - (void) memcpy (UA_Openssl_P_SHA256_SEED(ctx), seed->data, seed->length); - (void) memcpy (UA_Openssl_P_SHA256_SECRET(ctx), secret->data, secret->length); - /* A(0) = seed - A(n) = HMAC_HASH(secret, A(n-1)) */ - - if (HMAC (EVP_sha256(), secret->data, (int) secret->length, seed->data, - seed->length, ctx->A, NULL) == NULL) { - UA_free (ctx); - return NULL; - } +static void +channelContext_deleteContext_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc) { + UA_ByteString_clear(&cc->localSymSigningKey); + UA_ByteString_clear(&cc->localSymEncryptingKey); + UA_ByteString_clear(&cc->localSymIv); - return ctx; -} + UA_ByteString_clear(&cc->remoteSymSigningKey); + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + UA_ByteString_clear(&cc->remoteSymIv); -static UA_StatusCode -P_SHA256_Hash_Generate (UA_Openssl_P_SHA256_Ctx * ctx, - UA_Byte * pHas - ) { - /* Calculate P_SHA256(n) = HMAC_SHA256(secret, A(n)+seed) */ - if (HMAC (EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen, - ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } + mbedtls_x509_crt_free(&cc->remoteCertificate); - /* Calculate A(n) = HMAC_SHA256(secret, A(n-1)) */ - if (HMAC (EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen, - ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - return UA_STATUSCODE_GOOD; + UA_free(cc); } -UA_StatusCode -UA_Openssl_Random_Key_PSHA256_Derive (const UA_ByteString * secret, - const UA_ByteString * seed, - UA_ByteString * out) { - size_t keyLen = out->length; - size_t iter = keyLen/32 + ((keyLen%32)?1:0); - size_t bufferLen = iter * 32; - size_t i; - UA_StatusCode st; +static UA_StatusCode +channelContext_newContext_sp_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **pp_contextData) { + if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - UA_Byte * pBuffer = (UA_Byte *) UA_malloc (bufferLen); - if (pBuffer == NULL) { + /* Allocate the channel context */ + *pp_contextData = UA_malloc(sizeof(Aes128Sha256PsaOaep_ChannelContext)); + if(*pp_contextData == NULL) return UA_STATUSCODE_BADOUTOFMEMORY; - } - UA_Openssl_P_SHA256_Ctx * ctx = P_SHA256_Ctx_Create (secret, seed); - if (ctx == NULL) { - UA_free (pBuffer); - return UA_STATUSCODE_BADOUTOFMEMORY; - } + Aes128Sha256PsaOaep_ChannelContext *cc = (Aes128Sha256PsaOaep_ChannelContext *)*pp_contextData; - for (i = 0; i < iter; i++) { - st = P_SHA256_Hash_Generate (ctx, pBuffer + (i * 32)); - if (st != UA_STATUSCODE_GOOD) { - UA_free (pBuffer); - UA_free (ctx); - return st; - } - } + /* Initialize the channel context */ + cc->policyContext = (Aes128Sha256PsaOaep_PolicyContext *)securityPolicy->policyContext; - (void) memcpy (out->data, pBuffer, keyLen); - UA_free (pBuffer); - UA_free (ctx); - return UA_STATUSCODE_GOOD; -} + UA_ByteString_init(&cc->localSymSigningKey); + UA_ByteString_init(&cc->localSymEncryptingKey); + UA_ByteString_init(&cc->localSymIv); -/* return the key bytes */ -UA_StatusCode -UA_Openssl_RSA_Public_GetKeyLength (X509 * publicKeyX509, - UA_Int32 * keyLen) { - EVP_PKEY * evpKey = X509_get_pubkey (publicKeyX509); - if (evpKey == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - RSA * rsa = get_pkey_rsa (evpKey); - *keyLen = RSA_size(rsa); - EVP_PKEY_free (evpKey); - - return UA_STATUSCODE_GOOD; -} + UA_ByteString_init(&cc->remoteSymSigningKey); + UA_ByteString_init(&cc->remoteSymEncryptingKey); + UA_ByteString_init(&cc->remoteSymIv); -UA_StatusCode -UA_Openssl_RSA_Private_GetKeyLength (EVP_PKEY * privateKey, - UA_Int32 * keyLen) { - if (privateKey == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } - *keyLen = RSA_size(get_pkey_rsa(privateKey)); + mbedtls_x509_crt_init(&cc->remoteCertificate); - return UA_STATUSCODE_GOOD; + // TODO: this can be optimized so that we dont allocate memory before parsing the certificate + UA_StatusCode retval = parseRemoteCertificate_sp_aes128sha256rsaoaep(cc, remoteCertificate); + if(retval != UA_STATUSCODE_GOOD) { + channelContext_deleteContext_sp_aes128sha256rsaoaep(cc); + *pp_contextData = NULL; + } + return retval; } -static UA_StatusCode -UA_Openssl_RSA_Private_Sign (const UA_ByteString * message, - EVP_PKEY * privateKey, - const EVP_MD * evpMd, - UA_Int16 padding, - UA_ByteString * outSignature) { - EVP_MD_CTX * mdctx = NULL; - int opensslRet; - EVP_PKEY_CTX * evpKeyCtx; - UA_StatusCode ret; - - mdctx = EVP_MD_CTX_create (); - if (mdctx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } +static UA_StatusCode +channelContext_setLocalSymEncryptingKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - if (privateKey == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } - opensslRet = EVP_DigestSignInit (mdctx, &evpKeyCtx, evpMd, NULL, privateKey); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - EVP_PKEY_CTX_set_rsa_padding (evpKeyCtx, padding); + UA_ByteString_clear(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); +} - opensslRet = EVP_DigestSignUpdate (mdctx, message->data, message->length); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - opensslRet = EVP_DigestSignFinal (mdctx, outSignature->data, &outSignature->length); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } +static UA_StatusCode +channelContext_setLocalSymSigningKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - ret = UA_STATUSCODE_GOOD; -errout: - if (mdctx != NULL) { - EVP_MD_CTX_destroy (mdctx); - } - return ret; + UA_ByteString_clear(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); } -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_SHA256_Sign (const UA_ByteString * message, - EVP_PKEY * privateKey, - UA_ByteString * outSignature) { - return UA_Openssl_RSA_Private_Sign (message, privateKey, EVP_sha256(), - NID_sha256, outSignature); -} - -UA_StatusCode -UA_OpenSSL_HMAC_SHA256_Verify (const UA_ByteString * message, - const UA_ByteString * key, - const UA_ByteString * signature - ) { - unsigned char buf[SHA256_DIGEST_LENGTH] = {0}; - UA_ByteString mac = {SHA256_DIGEST_LENGTH, buf}; - if (HMAC (EVP_sha256(), key->data, (int) key->length, message->data, message->length, - mac.data, (unsigned int *) &mac.length) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - if (UA_ByteString_equal (signature, &mac)) { - return UA_STATUSCODE_GOOD; - } - else { +static UA_StatusCode +channelContext_setLocalSymIv_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *iv) { + if(iv == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - } + + UA_ByteString_clear(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); } -UA_StatusCode -UA_OpenSSL_HMAC_SHA256_Sign (const UA_ByteString * message, - const UA_ByteString * key, - UA_ByteString * signature - ) { - if (HMAC (EVP_sha256(), key->data, (int) key->length, message->data, - message->length, - signature->data, (unsigned int *) &(signature->length)) == NULL) { +static UA_StatusCode +channelContext_setRemoteSymEncryptingKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) return UA_STATUSCODE_BADINTERNALERROR; - } - return UA_STATUSCODE_GOOD; -} -static UA_StatusCode -UA_OpenSSL_Decrypt (const UA_ByteString * iv, - const UA_ByteString * key, - const EVP_CIPHER * cipherAlg, - UA_ByteString * data /* [in/out]*/) { - UA_ByteString ivCopy = {0, NULL}; - UA_ByteString cipherTxt = {0, NULL}; - EVP_CIPHER_CTX * ctx = NULL; - UA_StatusCode ret; - int opensslRet; - int outLen; - int tmpLen; + UA_ByteString_clear(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +} - /* copy the IV because the AES_cbc_encrypt function overwrites it. */ +static UA_StatusCode +channelContext_setRemoteSymSigningKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - ret = UA_ByteString_copy (iv, &ivCopy); - if (ret != UA_STATUSCODE_GOOD) { - goto errout; - } + UA_ByteString_clear(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +} - ret = UA_ByteString_copy (data, &cipherTxt); - if (ret != UA_STATUSCODE_GOOD) { - goto errout; - } - - ctx = EVP_CIPHER_CTX_new (); - if (ctx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } - - /* call EVP_* to decrypt */ - - opensslRet = EVP_DecryptInit_ex (ctx, cipherAlg, NULL, key->data, ivCopy.data); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - /* EVP_DecryptFinal() will return an error code if padding is enabled - * and the final block is not correctly formatted. - */ - EVP_CIPHER_CTX_set_padding (ctx, 0); - opensslRet = EVP_DecryptUpdate (ctx, data->data, &outLen, - cipherTxt.data, (int) cipherTxt.length); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - opensslRet = EVP_DecryptFinal_ex (ctx, data->data + outLen, &tmpLen); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - outLen += tmpLen; - data->length = (size_t) outLen; - ret = UA_STATUSCODE_GOOD; +static UA_StatusCode +channelContext_setRemoteSymIv_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *iv) { + if(iv == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -errout: - UA_ByteString_deleteMembers (&ivCopy); - UA_ByteString_deleteMembers (&cipherTxt); - if (ctx != NULL) { - EVP_CIPHER_CTX_free(ctx); - } - return ret; + UA_ByteString_clear(&cc->remoteSymIv); + return UA_ByteString_copy(iv, &cc->remoteSymIv); } static UA_StatusCode -UA_OpenSSL_Encrypt (const UA_ByteString * iv, - const UA_ByteString * key, - const EVP_CIPHER * cipherAlg, - UA_ByteString * data /* [in/out]*/ - ) { +channelContext_compareCertificate_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc, + const UA_ByteString *certificate) { + if(cc == NULL || certificate == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - UA_ByteString ivCopy = {0, NULL}; - UA_ByteString plainTxt = {0, NULL}; - EVP_CIPHER_CTX * ctx = NULL; - UA_StatusCode ret; - int opensslRet; - int outLen; - int tmpLen; + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); + int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length); + if(mbedErr) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - /* copy the IV because the AES_cbc_encrypt function overwrites it. */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(cert.raw.len != cc->remoteCertificate.raw.len || + memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0) + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; - ret = UA_ByteString_copy (iv, &ivCopy); - if (ret != UA_STATUSCODE_GOOD) { - goto errout; - } + mbedtls_x509_crt_free(&cert); + return retval; +} - ret = UA_ByteString_copy (data, &plainTxt); - if (ret != UA_STATUSCODE_GOOD) { - goto errout; - } - - ctx = EVP_CIPHER_CTX_new (); - if (ctx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto errout; - } +static void +clear_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy) { + if(securityPolicy == NULL) + return; - /* call EVP_* to encrypt */ + UA_ByteString_clear(&securityPolicy->localCertificate); - opensslRet = EVP_EncryptInit_ex (ctx, cipherAlg, NULL, key->data, ivCopy.data); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - opensslRet = EVP_EncryptUpdate (ctx, data->data, &outLen, - plainTxt.data, (int) plainTxt.length); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - /* - * Buffer passed to EVP_EncryptFinal() must be after data just - * encrypted to avoid overwriting it. - */ - opensslRet = EVP_EncryptFinal_ex(ctx, data->data + outLen, &tmpLen); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - outLen += tmpLen; - data->length = (size_t) outLen; - ret = UA_STATUSCODE_GOOD; + if(securityPolicy->policyContext == NULL) + return; -errout: - UA_ByteString_deleteMembers (&ivCopy); - UA_ByteString_deleteMembers (&plainTxt); - if (ctx != NULL) { - EVP_CIPHER_CTX_free(ctx); - } - return ret; -} + /* delete all allocated members in the context */ + Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *) + securityPolicy->policyContext; -UA_StatusCode -UA_OpenSSL_AES_256_CBC_Decrypt (const UA_ByteString * iv, - const UA_ByteString * key, - UA_ByteString * data /* [in/out]*/ - ) { - return UA_OpenSSL_Decrypt (iv, key, EVP_aes_256_cbc (), data); -} + mbedtls_ctr_drbg_free(&pc->drbgContext); + mbedtls_entropy_free(&pc->entropyContext); + mbedtls_pk_free(&pc->localPrivateKey); + mbedtls_md_free(&pc->sha256MdContext); + UA_ByteString_clear(&pc->localCertThumbprint); -UA_StatusCode -UA_OpenSSL_AES_256_CBC_Encrypt (const UA_ByteString * iv, - const UA_ByteString * key, - UA_ByteString * data /* [in/out]*/ - ) { - return UA_OpenSSL_Encrypt (iv, key, EVP_aes_256_cbc (), data); + UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Deleted members of EndpointContext for sp_aes128sha256rsaoaep"); + + UA_free(pc); + securityPolicy->policyContext = NULL; } -UA_StatusCode -UA_OpenSSL_X509_compare (const UA_ByteString * cert, - const X509 * bcert) { - X509 * acert = UA_OpenSSL_LoadCertificate(cert); - if (acert == NULL) { - return UA_STATUSCODE_BADCERTIFICATEINVALID; - } - int opensslRet = X509_cmp (acert, bcert); - X509_free (acert); +static UA_StatusCode +updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy, + const UA_ByteString newCertificate, + const UA_ByteString newPrivateKey) { + if(securityPolicy == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - if (opensslRet == 0) - return UA_STATUSCODE_GOOD; - return UA_STATUSCODE_UNCERTAINSUBNORMAL; -} + if(securityPolicy->policyContext == NULL) + return UA_STATUSCODE_BADINTERNALERROR; -UA_StatusCode -UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (const UA_ByteString * msg, - X509 * publicKeyX509, - const UA_ByteString * signature) { - return UA_OpenSSL_RSA_Public_Verify (msg, EVP_sha1(), publicKeyX509, - NID_sha1, signature); -} + Aes128Sha256PsaOaep_PolicyContext *pc = + (Aes128Sha256PsaOaep_PolicyContext *) securityPolicy->policyContext; -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (const UA_ByteString * message, - EVP_PKEY * privateKey, - UA_ByteString * outSignature) { - return UA_Openssl_RSA_Private_Sign (message, privateKey, EVP_sha1(), - NID_sha1, outSignature); -} + UA_ByteString_clear(&securityPolicy->localCertificate); -static UA_Openssl_P_SHA1_Ctx * -P_SHA1_Ctx_Create (const UA_ByteString * secret, - const UA_ByteString * seed) { - size_t size = (UA_Int32)sizeof (UA_Openssl_P_SHA1_Ctx) + secret->length + - seed->length; - UA_Openssl_P_SHA1_Ctx * ctx = (UA_Openssl_P_SHA1_Ctx *) UA_malloc (size); - if (ctx == NULL) { - return NULL; - } + UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate, + newCertificate.length + 1); + if(retval != UA_STATUSCODE_GOOD) + return retval; + memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length); + securityPolicy->localCertificate.data[newCertificate.length] = '\0'; + securityPolicy->localCertificate.length--; - ctx->secretLen = secret->length; - ctx->seedLen = seed->length; - (void) memcpy (UA_Openssl_P_SHA1_SEED(ctx), seed->data, seed->length); - (void) memcpy (UA_Openssl_P_SHA1_SECRET(ctx), secret->data, secret->length); - /* A(0) = seed - A(n) = HMAC_HASH(secret, A(n-1)) */ - - if (HMAC (EVP_sha1(), secret->data, (int) secret->length, seed->data, - seed->length, ctx->A, NULL) == NULL) { - UA_free (ctx); - return NULL; + /* Set the new private key */ + mbedtls_pk_free(&pc->localPrivateKey); + mbedtls_pk_init(&pc->localPrivateKey); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data, + newPrivateKey.length, NULL, 0); +#else + int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data, + newPrivateKey.length, NULL, 0, mbedtls_entropy_func, &pc->drbgContext); +#endif + if(mbedErr) { + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + goto error; } - return ctx; -} + retval = asym_makeThumbprint_sp_aes128sha256rsaoaep(securityPolicy, + &securityPolicy->localCertificate, + &pc->localCertThumbprint); + if(retval != UA_STATUSCODE_GOOD) + goto error; -static UA_StatusCode -P_SHA1_Hash_Generate (UA_Openssl_P_SHA1_Ctx * ctx, - UA_Byte * pHas - ) { - /* Calculate P_SHA1(n) = HMAC_SHA1(secret, A(n)+seed) */ - if (HMAC (EVP_sha1 (), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen, - ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } + return retval; - /* Calculate A(n) = HMAC_SHA1(secret, A(n-1)) */ - if (HMAC (EVP_sha1(), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen, - ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - return UA_STATUSCODE_GOOD; + error: + UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Could not update certificate and private key"); + if(securityPolicy->policyContext != NULL) + clear_sp_aes128sha256rsaoaep(securityPolicy); + return retval; } -UA_StatusCode -UA_Openssl_Random_Key_PSHA1_Derive (const UA_ByteString * secret, - const UA_ByteString * seed, - UA_ByteString * out) { - size_t keyLen = out->length; - size_t iter = keyLen / SHA1_DIGEST_LENGTH + ((keyLen % SHA1_DIGEST_LENGTH)?1:0); - size_t bufferLen = iter * SHA1_DIGEST_LENGTH; - UA_Byte * pBuffer = (UA_Byte *) UA_malloc (bufferLen); - if (pBuffer == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } +static UA_StatusCode +policyContext_newContext_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy, + const UA_ByteString localPrivateKey) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(securityPolicy == NULL) + return UA_STATUSCODE_BADINTERNALERROR; - UA_Openssl_P_SHA1_Ctx * ctx = P_SHA1_Ctx_Create (secret, seed); - if (ctx == NULL) { - UA_free (pBuffer); - return UA_STATUSCODE_BADOUTOFMEMORY; + if (localPrivateKey.length == 0) { + UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Can not initialize security policy. Private key is empty."); + return UA_STATUSCODE_BADINVALIDARGUMENT; } - - size_t i; - UA_StatusCode st; - for (i = 0; i < iter; i++) { - st = P_SHA1_Hash_Generate (ctx, pBuffer + (i * SHA1_DIGEST_LENGTH)); - if (st != UA_STATUSCODE_GOOD) { - UA_free (pBuffer); - UA_free (ctx); - return st; - } + Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *) + UA_malloc(sizeof(Aes128Sha256PsaOaep_PolicyContext)); + securityPolicy->policyContext = (void *)pc; + if(!pc) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + goto error; } - (void) memcpy (out->data, pBuffer, keyLen); - UA_free (pBuffer); - UA_free (ctx); - - return UA_STATUSCODE_GOOD; -} + /* Initialize the PolicyContext */ + memset(pc, 0, sizeof(Aes128Sha256PsaOaep_PolicyContext)); + mbedtls_ctr_drbg_init(&pc->drbgContext); + mbedtls_entropy_init(&pc->entropyContext); + mbedtls_pk_init(&pc->localPrivateKey); + mbedtls_md_init(&pc->sha256MdContext); -UA_StatusCode -UA_OpenSSL_HMAC_SHA1_Verify (const UA_ByteString * message, - const UA_ByteString * key, - const UA_ByteString * signature - ) { - unsigned char buf[SHA1_DIGEST_LENGTH] = {0}; - UA_ByteString mac = {SHA1_DIGEST_LENGTH, buf}; + /* Initialized the message digest */ + const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256); + if(mbedErr) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + goto error; + } - if (HMAC (EVP_sha1(), key->data, (int) key->length, message->data, message->length, - mac.data, (unsigned int *) &mac.length) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; + mbedErr = mbedtls_entropy_self_test(0); + + if(mbedErr) { + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + goto error; } - if (UA_ByteString_equal (signature, &mac)) { - return UA_STATUSCODE_GOOD; + + /* Seed the RNG */ + char *personalization = "open62541-drbg"; + mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func, + &pc->entropyContext, + (const unsigned char *)personalization, 14); + if(mbedErr) { + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + goto error; } - else { - return UA_STATUSCODE_BADINTERNALERROR; - } -} -UA_StatusCode -UA_OpenSSL_HMAC_SHA1_Sign (const UA_ByteString * message, - const UA_ByteString * key, - UA_ByteString * signature - ) { - if (HMAC (EVP_sha1(), key->data, (int) key->length, message->data, - message->length, - signature->data, (unsigned int *) &(signature->length)) == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; + /* Set the private key */ + mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext); + if(mbedErr) { + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + goto error; } + + /* Set the local certificate thumbprint */ + retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH); + if(retval != UA_STATUSCODE_GOOD) + goto error; + retval = asym_makeThumbprint_sp_aes128sha256rsaoaep(securityPolicy, + &securityPolicy->localCertificate, + &pc->localCertThumbprint); + if(retval != UA_STATUSCODE_GOOD) + goto error; + return UA_STATUSCODE_GOOD; -} -UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_Decrypt (UA_ByteString * data, - EVP_PKEY * privateKey) { - return UA_Openssl_RSA_Private_Decrypt (data, privateKey, - RSA_PKCS1_PADDING); +error: + UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Could not create securityContext: %s", UA_StatusCode_name(retval)); + if(securityPolicy->policyContext != NULL) + clear_sp_aes128sha256rsaoaep(securityPolicy); + return retval; } UA_StatusCode -UA_Openssl_RSA_PKCS1_V15_Encrypt (UA_ByteString * data, - size_t paddingSize, - X509 * publicX509) { - UA_ByteString message; - UA_StatusCode ret; - - ret = UA_ByteString_copy (data, &message); - if (ret != UA_STATUSCODE_GOOD) { - return ret; - } - ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509, - RSA_PKCS1_PADDING, - paddingSize, - data); - UA_ByteString_deleteMembers (&message); - return ret; -} +UA_SecurityPolicy_Aes128Sha256RsaOaep(UA_SecurityPolicy *policy, const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey, const UA_Logger *logger) { + memset(policy, 0, sizeof(UA_SecurityPolicy)); + policy->logger = logger; -UA_StatusCode -UA_OpenSSL_AES_128_CBC_Decrypt (const UA_ByteString * iv, - const UA_ByteString * key, - UA_ByteString * data /* [in/out]*/ - ) { - return UA_OpenSSL_Decrypt (iv, key, EVP_aes_128_cbc (), data); -} + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep"); -UA_StatusCode -UA_OpenSSL_AES_128_CBC_Encrypt (const UA_ByteString * iv, - const UA_ByteString * key, - UA_ByteString * data /* [in/out]*/ - ) { - return UA_OpenSSL_Encrypt (iv, key, EVP_aes_128_cbc (), data); -} + UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule; -EVP_PKEY * -UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey) { - const unsigned char * pkData = privateKey->data; - long len = (long) privateKey->length; + UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate); - EVP_PKEY *result = NULL; + if (retval != UA_STATUSCODE_GOOD) + return retval; - if (len > 1 && pkData[0] == 0x30 && pkData[1] == 0x82) { // Magic number for DER encoded keys - result = d2i_PrivateKey(EVP_PKEY_RSA, NULL, - &pkData, len); - } else { - BIO *bio = NULL; -#if OPENSSL_VERSION_NUMBER < 0x1000207fL - bio = BIO_new_mem_buf((void *) privateKey->data, (int) privateKey->length); -#else - bio = BIO_new_mem_buf((const void *) privateKey->data, (int) privateKey->length); -#endif - result = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - BIO_free(bio); - } + /* AsymmetricModule */ + UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm = + &asymmetricModule->cryptoModule.signatureAlgorithm; + asym_signatureAlgorithm->uri = + UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0"); + asym_signatureAlgorithm->verify = + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_aes128sha256rsaoaep; + asym_signatureAlgorithm->sign = + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_aes128sha256rsaoaep; + asym_signatureAlgorithm->getLocalSignatureSize = + (size_t (*)(const void *))asym_getLocalSignatureSize_sp_aes128sha256rsaoaep; + asym_signatureAlgorithm->getRemoteSignatureSize = + (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_aes128sha256rsaoaep; + asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function + asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function - return result; -} + UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm = + &asymmetricModule->cryptoModule.encryptionAlgorithm; + asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); + asym_encryptionAlgorithm->encrypt = + (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_aes128sha256rsaoaep; + asym_encryptionAlgorithm->decrypt = + (UA_StatusCode(*)(void *, UA_ByteString *)) asym_decrypt_sp_aes128sha256rsaoaep; + asym_encryptionAlgorithm->getLocalKeyLength = + (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_aes128sha256rsaoaep; + asym_encryptionAlgorithm->getRemoteKeyLength = + (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_aes128sha256rsaoaep; + asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const void *))asym_getRemoteBlockSize_sp_aes128sha256rsaoaep; + asym_encryptionAlgorithm->getRemotePlainTextBlockSize = + (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_aes128sha256rsaoaep; -X509 * -UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate) { - X509 * result = NULL; - const unsigned char *pData = certificate->data; + asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_aes128sha256rsaoaep; + asymmetricModule->compareCertificateThumbprint = + asymmetricModule_compareCertificateThumbprint_sp_aes128sha256rsaoaep; - if (certificate->length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files - result = UA_OpenSSL_LoadDerCertificate(certificate); - } else { - result = UA_OpenSSL_LoadPemCertificate(certificate); - } + /* SymmetricModule */ + symmetricModule->generateKey = sym_generateKey_sp_aes128sha256rsaoaep; + symmetricModule->generateNonce = sym_generateNonce_sp_aes128sha256rsaoaep; - return result; -} + UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm = + &symmetricModule->cryptoModule.signatureAlgorithm; + sym_signatureAlgorithm->uri = + UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); + sym_signatureAlgorithm->verify = + (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_aes128sha256rsaoaep; + sym_signatureAlgorithm->sign = + (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_aes128sha256rsaoaep; + sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_aes128sha256rsaoaep; + sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_aes128sha256rsaoaep; + sym_signatureAlgorithm->getLocalKeyLength = + (size_t (*)(const void *))sym_getSigningKeyLength_sp_aes128sha256rsaoaep; + sym_signatureAlgorithm->getRemoteKeyLength = + (size_t (*)(const void *))sym_getSigningKeyLength_sp_aes128sha256rsaoaep; -X509 * -UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate) { - const unsigned char *pData = certificate->data; - return d2i_X509(NULL, &pData, (long) certificate->length); -} + UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = + &symmetricModule->cryptoModule.encryptionAlgorithm; + sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc"); + sym_encryptionAlgorithm->encrypt = + (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_aes128sha256rsaoaep; + sym_encryptionAlgorithm->decrypt = + (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_aes128sha256rsaoaep; + sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_aes128sha256rsaoaep; + sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_aes128sha256rsaoaep; + sym_encryptionAlgorithm->getRemoteBlockSize = + (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_aes128sha256rsaoaep; + sym_encryptionAlgorithm->getRemotePlainTextBlockSize = + (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_aes128sha256rsaoaep; + symmetricModule->secureChannelNonceLength = 32; -X509 * -UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate) { - X509 * result = NULL; + // Use the same signature algorithm as the asymmetric component for certificate signing (see standard) + policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; - BIO* bio = NULL; -#if OPENSSL_VERSION_NUMBER < 0x1000207fL - bio = BIO_new_mem_buf((void *) certificate->data, (int) certificate->length); -#else - bio = BIO_new_mem_buf((const void *) certificate->data, (int) certificate->length); -#endif - result = PEM_read_bio_X509(bio, NULL, NULL, NULL); - BIO_free(bio); + /* ChannelModule */ + channelModule->newContext = channelContext_newContext_sp_aes128sha256rsaoaep; + channelModule->deleteContext = (void (*)(void *)) + channelContext_deleteContext_sp_aes128sha256rsaoaep; - return result; -} + channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymEncryptingKey_sp_aes128sha256rsaoaep; + channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymSigningKey_sp_aes128sha256rsaoaep; + channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymIv_sp_aes128sha256rsaoaep; -UA_StatusCode -UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString *target) { - X509 *cert = UA_OpenSSL_LoadCertificate(certificate); + channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymEncryptingKey_sp_aes128sha256rsaoaep; + channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymSigningKey_sp_aes128sha256rsaoaep; + channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymIv_sp_aes128sha256rsaoaep; - if (!cert) - return UA_STATUSCODE_BADINVALIDARGUMENT; + channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *)) + channelContext_compareCertificate_sp_aes128sha256rsaoaep; - unsigned char *derData = NULL; - int length = i2d_X509(cert, &derData); - X509_free(cert); + policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep; + policy->clear = clear_sp_aes128sha256rsaoaep; - if (length > 0) { - UA_ByteString temp; - temp.length = (size_t) length; - temp.data = derData; - UA_ByteString_copy(&temp, target); - OPENSSL_free(derData); - return UA_STATUSCODE_GOOD; - } + UA_StatusCode res = policyContext_newContext_sp_aes128sha256rsaoaep(policy, localPrivateKey); + if(res != UA_STATUSCODE_GOOD) + clear_sp_aes128sha256rsaoaep(policy); - return UA_STATUSCODE_BADINVALIDARGUMENT; + return res; } - #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/openssl/ua_openssl_basic128rsa15.c" ***********************************/ +/**** amalgamated original file "/plugins/crypto/mbedtls/ua_pki_mbedtls.c" ****/ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. * - * Copyright 2020 (c) Wind River Systems, Inc. - * Copyright 2020 (c) basysKom GmbH + * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB */ -/* -modification history --------------------- -18mar20,lan written -*/ - -#ifdef UA_ENABLE_ENCRYPTION_OPENSSL +#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS +#include <mbedtls/x509.h> +#include <mbedtls/x509_crt.h> +#include <mbedtls/error.h> +#include <mbedtls/version.h> -#include <openssl/x509.h> -#include <openssl/rand.h> -#include <openssl/evp.h> +#define REMOTECERTIFICATETRUSTED 1 +#define ISSUERKNOWN 2 +#define DUALPARENT 3 +#define PARENTFOUND 4 -#define UA_SHA1_LENGTH 20 -#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN 11 -#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH 16 -#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE 16 -#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE 16 -#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH 16 -#define UA_SHA1_LENGTH 20 +/* Find binary substring. Taken and adjusted from + * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */ -typedef struct { - EVP_PKEY * localPrivateKey; - UA_ByteString localCertThumbprint; - const UA_Logger * logger; -} Policy_Context_Basic128Rsa15; +static const unsigned char * +bstrchr(const unsigned char *s, const unsigned char ch, size_t l) { + /* find first occurrence of c in char s[] for length l*/ + for(; l > 0; ++s, --l) { + if(*s == ch) + return s; + } + return NULL; +} -typedef struct { - UA_ByteString localSymSigningKey; - UA_ByteString localSymEncryptingKey; - UA_ByteString localSymIv; - UA_ByteString remoteSymSigningKey; - UA_ByteString remoteSymEncryptingKey; - UA_ByteString remoteSymIv; +static const unsigned char * +UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) { + /* find first occurrence of s2[] in s1[] for length l1*/ + const unsigned char *ss1 = s1; + const unsigned char *ss2 = s2; + /* handle special case */ + if(l1 == 0) + return (NULL); + if(l2 == 0) + return s1; - Policy_Context_Basic128Rsa15 * policyContext; - UA_ByteString remoteCertificate; - X509 * remoteCertificateX509; -} Channel_Context_Basic128Rsa15; + /* match prefix */ + for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL && + (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) { -static UA_StatusCode -UA_Policy_Basic128Rsa15_New_Context (UA_SecurityPolicy * securityPolicy, - const UA_ByteString localPrivateKey, - const UA_Logger * logger) { - Policy_Context_Basic128Rsa15 * context = (Policy_Context_Basic128Rsa15 *) - UA_malloc (sizeof (Policy_Context_Basic128Rsa15)); - if (context == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; + /* match rest of prefix */ + const unsigned char *sc1, *sc2; + for (sc1 = s1, sc2 = s2; ;) + if (++sc2 >= ss2+l2) + return s1; + else if (*++sc1 != *sc2) + break; } + return NULL; +} - context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); +// mbedTLS expects PEM data to be null terminated +// The data length parameter must include the null terminator +static UA_ByteString copyDataFormatAware(const UA_ByteString *data) +{ + UA_ByteString result; + UA_ByteString_init(&result); - if (!context->localPrivateKey) { - UA_free(context); - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + if (!data->length) + return result; - UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint ( - &securityPolicy->localCertificate, - &context->localCertThumbprint, true - ); - if (retval != UA_STATUSCODE_GOOD) { - EVP_PKEY_free(context->localPrivateKey); - UA_free (context); - return retval; + if (data->length && data->data[0] == '-') { + UA_ByteString_allocBuffer(&result, data->length + 1); + memcpy(result.data, data->data, data->length); + result.data[data->length] = '\0'; + } else { + UA_ByteString_copy(data, &result); } - context->logger = logger; - securityPolicy->policyContext = context; - - return UA_STATUSCODE_GOOD; -} + return result; +} -static void -UA_Policy_Basic128Rsa15_Clear_Context (UA_SecurityPolicy *policy) { - if (policy == NULL) { - return; - } - UA_ByteString_deleteMembers(&policy->localCertificate); +typedef struct { + /* If the folders are defined, we use them to reload the certificates during + * runtime */ + UA_String trustListFolder; + UA_String issuerListFolder; + UA_String revocationListFolder; - Policy_Context_Basic128Rsa15 * ctx = (Policy_Context_Basic128Rsa15 *) policy->policyContext; - if (ctx == NULL) { - return; - } + mbedtls_x509_crt certificateTrustList; + mbedtls_x509_crt certificateIssuerList; + mbedtls_x509_crl certificateRevocationList; +} CertInfo; - /* delete all allocated members in the context */ +#ifdef __linux__ /* Linux only so far */ - EVP_PKEY_free(ctx->localPrivateKey); - UA_ByteString_deleteMembers (&ctx->localCertThumbprint); - UA_free (ctx); +#include <dirent.h> +#include <limits.h> - return; -} +static UA_StatusCode +fileNamesFromFolder(const UA_String *folder, size_t *pathsSize, UA_String **paths) { + char buf[PATH_MAX + 1]; + if(folder->length > PATH_MAX) + return UA_STATUSCODE_BADINTERNALERROR; -/* create the channel context */ + memcpy(buf, folder->data, folder->length); + buf[folder->length] = 0; + + DIR *dir = opendir(buf); + if(!dir) + return UA_STATUSCODE_BADINTERNALERROR; -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_New_Context (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * remoteCertificate, - void ** channelContext) { - if (securityPolicy == NULL || remoteCertificate == NULL || - channelContext == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - Channel_Context_Basic128Rsa15 * context = (Channel_Context_Basic128Rsa15 *) - UA_malloc (sizeof (Channel_Context_Basic128Rsa15)); - if (context == NULL) { + *paths = (UA_String*)UA_Array_new(256, &UA_TYPES[UA_TYPES_STRING]); + if(*paths == NULL) { + closedir(dir); return UA_STATUSCODE_BADOUTOFMEMORY; } - UA_ByteString_init(&context->localSymSigningKey); - UA_ByteString_init(&context->localSymEncryptingKey); - UA_ByteString_init(&context->localSymIv); - UA_ByteString_init(&context->remoteSymSigningKey); - UA_ByteString_init(&context->remoteSymEncryptingKey); - UA_ByteString_init(&context->remoteSymIv); - - UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate, - remoteCertificate); - if (retval != UA_STATUSCODE_GOOD) { - UA_free (context); - return retval; + struct dirent *ent; + char buf2[PATH_MAX + 1]; + char *res = realpath(buf, buf2); + if(!res) { + closedir(dir); + return UA_STATUSCODE_BADINTERNALERROR; } - - /* decode to X509 */ - context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); - if (context->remoteCertificateX509 == NULL) { - UA_ByteString_clear (&context->remoteCertificate); - UA_free (context); - return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + size_t pathlen = strlen(buf2); + *pathsSize = 0; + while((ent = readdir (dir)) != NULL && *pathsSize < 256) { + if(ent->d_type != DT_REG) + continue; + buf2[pathlen] = '/'; + buf2[pathlen+1] = 0; + strcat(buf2, ent->d_name); + (*paths)[*pathsSize] = UA_STRING_ALLOC(buf2); + *pathsSize += 1; } + closedir(dir); - context->policyContext = (Policy_Context_Basic128Rsa15 *) - (securityPolicy->policyContext); - - *channelContext = context; - - UA_LOG_INFO (securityPolicy->logger, - UA_LOGCATEGORY_SECURITYPOLICY, - "The Basic128Rsa15 security policy channel with openssl is created."); - + if(*pathsSize == 0) { + UA_free(*paths); + *paths = NULL; + } return UA_STATUSCODE_GOOD; } -/* delete the channel context */ +static UA_StatusCode +reloadCertificates(CertInfo *ci) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + int err = 0; + int internalErrorFlag = 0; -static void -UA_ChannelModule_Basic128Rsa15_Delete_Context (void * channelContext) { - if (channelContext != NULL) { - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) - channelContext; - X509_free (cc->remoteCertificateX509); - UA_ByteString_deleteMembers (&cc->remoteCertificate); - UA_ByteString_deleteMembers (&cc->localSymSigningKey); - UA_ByteString_deleteMembers (&cc->localSymEncryptingKey); - UA_ByteString_deleteMembers (&cc->localSymIv); - UA_ByteString_deleteMembers (&cc->remoteSymSigningKey); - UA_ByteString_deleteMembers (&cc->remoteSymEncryptingKey); - UA_ByteString_deleteMembers (&cc->remoteSymIv); - UA_LOG_INFO (cc->policyContext->logger, - UA_LOGCATEGORY_SECURITYPOLICY, - "The Basic128Rsa15 security policy channel with openssl is deleted."); + /* Load the trustlists */ + if(ci->trustListFolder.length > 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list"); + mbedtls_x509_crt_free(&ci->certificateTrustList); + mbedtls_x509_crt_init(&ci->certificateTrustList); - UA_free (cc); + char f[PATH_MAX]; + memcpy(f, ci->trustListFolder.data, ci->trustListFolder.length); + f[ci->trustListFolder.length] = 0; + err = mbedtls_x509_crt_parse_path(&ci->certificateTrustList, f); + if(err == 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Loaded certificate from %s", f); + } else { + char errBuff[300]; + mbedtls_strerror(err, errBuff, 300); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to load certificate from %s, mbedTLS error: %s (error code: %d)", f, errBuff, err); + internalErrorFlag = 1; + } } -} -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_setLocalSymSigningKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* Load the revocationlists */ + if(ci->revocationListFolder.length > 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list"); + size_t pathsSize = 0; + UA_String *paths = NULL; + retval = fileNamesFromFolder(&ci->revocationListFolder, &pathsSize, &paths); + if(retval != UA_STATUSCODE_GOOD) + return retval; + mbedtls_x509_crl_free(&ci->certificateRevocationList); + mbedtls_x509_crl_init(&ci->certificateRevocationList); + for(size_t i = 0; i < pathsSize; i++) { + char f[PATH_MAX]; + memcpy(f, paths[i].data, paths[i].length); + f[paths[i].length] = 0; + err = mbedtls_x509_crl_parse_file(&ci->certificateRevocationList, f); + if(err == 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Loaded certificate from %.*s", + (int)paths[i].length, paths[i].data); + } else { + char errBuff[300]; + mbedtls_strerror(err, errBuff, 300); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to load certificate from %.*s, mbedTLS error: %s (error code: %d)", + (int)paths[i].length, paths[i].data, errBuff, err); + internalErrorFlag = 1; + } + } + UA_Array_delete(paths, pathsSize, &UA_TYPES[UA_TYPES_STRING]); + paths = NULL; + pathsSize = 0; } - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymSigningKey); - return UA_ByteString_copy(key, &cc->localSymSigningKey); -} - -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_setLocalSymEncryptingKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* Load the issuerlists */ + if(ci->issuerListFolder.length > 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list"); + mbedtls_x509_crt_free(&ci->certificateIssuerList); + mbedtls_x509_crt_init(&ci->certificateIssuerList); + char f[PATH_MAX]; + memcpy(f, ci->issuerListFolder.data, ci->issuerListFolder.length); + f[ci->issuerListFolder.length] = 0; + err = mbedtls_x509_crt_parse_path(&ci->certificateIssuerList, f); + if(err == 0) { + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Loaded certificate from %s", f); + } else { + char errBuff[300]; + mbedtls_strerror(err, errBuff, 300); + UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "Failed to load certificate from %s, mbedTLS error: %s (error code: %d)", + f, errBuff, err); + internalErrorFlag = 1; + } } - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); - return UA_ByteString_copy(key, &cc->localSymEncryptingKey); -} - -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_setLocalSymIv (void * channelContext, - const UA_ByteString * iv) { - if (iv == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + if(internalErrorFlag) { + retval = UA_STATUSCODE_BADINTERNALERROR; } - - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymIv); - return UA_ByteString_copy(iv, &cc->localSymIv); + return retval; } -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_setRemoteSymSigningKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +#endif - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); - return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +static UA_StatusCode +certificateVerification_allow(void *verificationContext, + const UA_ByteString *certificate) { + return UA_STATUSCODE_GOOD; } static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_setRemoteSymEncryptingKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +certificateVerification_verify(void *verificationContext, + const UA_ByteString *certificate) { + CertInfo *ci = (CertInfo*)verificationContext; + if(!ci) + return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); - return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); -} +#ifdef __linux__ /* Reload certificates if folder paths are specified */ + UA_StatusCode certFlag = reloadCertificates(ci); + if(certFlag != UA_STATUSCODE_GOOD) { + return certFlag; + } +#endif -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_setRemoteSymIv (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + if(ci->trustListFolder.length == 0 && + ci->issuerListFolder.length == 0 && + ci->revocationListFolder.length == 0 && + ci->certificateTrustList.raw.len == 0 && + ci->certificateIssuerList.raw.len == 0 && + ci->certificateRevocationList.raw.len == 0) { + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, + "PKI plugin unconfigured. Accepting the certificate."); + return UA_STATUSCODE_GOOD; } - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymIv); - return UA_ByteString_copy(key, &cc->remoteSymIv); -} + /* Parse the certificate */ + mbedtls_x509_crt remoteCertificate; -static UA_StatusCode -UA_ChannelModule_Basic128Rsa15_compareCertificate (const void * channelContext, - const UA_ByteString * certificate) { - if(channelContext == NULL || certificate == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* Temporary Object to parse the trustList */ + mbedtls_x509_crt *tempCert = NULL; - const Channel_Context_Basic128Rsa15 * cc = - (const Channel_Context_Basic128Rsa15 *) channelContext; - return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509); -} + /* Temporary Object to parse the revocationList */ + mbedtls_x509_crl *tempCrl = NULL; -static UA_StatusCode -UA_Asy_Basic128Rsa15_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * certificateThumbprint) { - if (securityPolicy == NULL || certificateThumbprint == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } - Policy_Context_Basic128Rsa15 *pc = (Policy_Context_Basic128Rsa15 *) - securityPolicy->policyContext; - if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) { - return UA_STATUSCODE_BADCERTIFICATEINVALID; - } - return UA_STATUSCODE_GOOD; -} + /* Temporary Object to identify the parent CA when there is no intermediate CA */ + mbedtls_x509_crt *parentCert = NULL; -/* Generates a thumbprint for the specified certificate */ + /* Temporary Object to identify the parent CA when there is intermediate CA */ + mbedtls_x509_crt *parentCert_2 = NULL; -static UA_StatusCode -UA_Asy_Basic128Rsa15_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * certificate, - UA_ByteString * thumbprint) { - return UA_Openssl_X509_GetCertificateThumbprint (certificate, - thumbprint, false); -} + /* Flag value to identify if the issuer certificate is found */ + int issuerKnown = 0; -static size_t -UA_AsySig_Basic128Rsa15_getRemoteSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* Flag value to identify if the parent certificate found */ + int parentFound = 0; + + mbedtls_x509_crt_init(&remoteCertificate); + int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data, + certificate->length); + if(mbedErr) { + /* char errBuff[300]; */ + /* mbedtls_strerror(mbedErr, errBuff, 300); */ + /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */ + /* "Could not parse the remote certificate with error: %s", errBuff); */ + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; } - const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen; -} + /* Verify */ + mbedtls_x509_crt_profile crtProfile = { + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256), + 0xFFFFFF, 0x000000, 128 * 8 // in bits + }; // TODO: remove magic numbers -static size_t -UA_AsySig_Basic128Rsa15_getLocalSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + uint32_t flags = 0; + mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, + &ci->certificateTrustList, + &ci->certificateRevocationList, + &crtProfile, NULL, &flags, NULL, NULL); + + /* Flag to check if the remote certificate is trusted or not */ + int TRUSTED = 0; + + /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */ + if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) { + for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) { + if(remoteCertificate.raw.len == tempCert->raw.len && + memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) { + TRUSTED = REMOTECERTIFICATETRUSTED; + break; + } + } } - Policy_Context_Basic128Rsa15 * pc = - (Policy_Context_Basic128Rsa15 *) securityPolicy->policyContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + /* If the remote certificate is present in the trustList then check if the issuer certificate + * of remoteCertificate is present in issuerList */ + if(TRUSTED && mbedErr) { + mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, + &ci->certificateIssuerList, + &ci->certificateRevocationList, + &crtProfile, NULL, &flags, NULL, NULL); - return (size_t) keyLen; -} + /* Check if the parent certificate has a CRL file available */ + if(!mbedErr) { + /* Flag value to identify if that there is an intermediate CA present */ + int dualParent = 0; -static UA_StatusCode -UA_AsySig_Basic128Rsa15_Verify (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - const UA_ByteString * signature) { - if (securityPolicy == NULL || message == NULL || signature == NULL || - channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* Identify the topmost parent certificate for the remoteCertificate */ + for(parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) { + if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) { + for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) { + if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) { + dualParent = DUALPARENT; + break; + } + } + parentFound = PARENTFOUND; + } - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (message, - cc->remoteCertificateX509, signature); + if(parentFound == PARENTFOUND) + break; + } - return retval; -} + /* Check if there is an intermediate certificate between the topmost parent + * certificate and child certificate + * If yes the topmost parent certificate is to be checked whether it has a + * CRL file avaiable */ + if(dualParent == DUALPARENT && parentFound == PARENTFOUND) { + parentCert = parentCert_2; + } -static UA_StatusCode -UA_AsySig_Basic128Rsa15_Sign (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* If a parent certificate is found traverse the revocationList and identify + * if there is any CRL file that corresponds to the parentCertificate */ + if(parentFound == PARENTFOUND) { + tempCrl = &ci->certificateRevocationList; + while(tempCrl != NULL) { + if(tempCrl->version != 0 && + tempCrl->issuer_raw.len == parentCert->subject_raw.len && + memcmp(tempCrl->issuer_raw.p, + parentCert->subject_raw.p, + tempCrl->issuer_raw.len) == 0) { + issuerKnown = ISSUERKNOWN; + break; + } - Policy_Context_Basic128Rsa15 * pc = - (Policy_Context_Basic128Rsa15 *) securityPolicy->policyContext; - return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (message, pc->localPrivateKey, - signature); -} + tempCrl = tempCrl->next; + } -static size_t -UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* If the CRL file corresponding to the parent certificate is not present + * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */ + if(!issuerKnown) { + return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; + } - const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; -} + } + + } -static size_t -UA_AsymEn_Basic128Rsa15_getRemoteBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; } + else if(!mbedErr && !TRUSTED) { + /* This else if section is to identify if the parent certificate which is present in trustList + * has CRL file corresponding to it */ - const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen; -} + /* Identify the parent certificate of the remoteCertificate */ + for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) { + if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) { + parentFound = PARENTFOUND; + break; + } -static size_t -UA_AsymEn_Basic128Rsa15_getRemoteKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; + } - const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen * 8; -} + /* If the parent certificate is found traverse the revocationList and identify + * if there is any CRL file that corresponds to the parentCertificate */ + if(parentFound == PARENTFOUND && + memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) { + tempCrl = &ci->certificateRevocationList; + while(tempCrl != NULL) { + if(tempCrl->version != 0 && + tempCrl->issuer_raw.len == parentCert->subject_raw.len && + memcmp(tempCrl->issuer_raw.p, + parentCert->subject_raw.p, + tempCrl->issuer_raw.len) == 0) { + issuerKnown = ISSUERKNOWN; + break; + } -static size_t -UA_AsymEn_Basic128Rsa15_getLocalKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; + tempCrl = tempCrl->next; + } - Policy_Context_Basic128Rsa15 * pc = - (Policy_Context_Basic128Rsa15 *) securityPolicy->policyContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + /* If the CRL file corresponding to the parent certificate is not present + * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */ + if(!issuerKnown) { + return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN; + } - return (size_t) keyLen * 8; -} + } -static UA_StatusCode -UA_AsymEn_Basic128Rsa15_Decrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if (securityPolicy == NULL || channelContext == NULL || data == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; } - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - UA_StatusCode ret = UA_Openssl_RSA_PKCS1_V15_Decrypt (data, - cc->policyContext->localPrivateKey); - return ret; -} + // TODO: Extend verification -static UA_StatusCode -UA_AsymEn_Basic128Rsa15_Encrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if (securityPolicy == NULL || channelContext == NULL || - data == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* This condition will check whether the certificate is a User certificate + * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and + * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate + * shall be condidered as CA Certificate and cannot be used to establish a + * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js + * for more details */ +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) && + (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) { + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; + } +#else + if((remoteCertificate.private_key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) && + (remoteCertificate.private_key_usage & MBEDTLS_X509_KU_CRL_SIGN)) { + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; + } +#endif - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - return UA_Openssl_RSA_PKCS1_V15_Encrypt (data, - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN, - cc->remoteCertificateX509); -} -static UA_StatusCode -UA_Sym_Basic128Rsa15_generateNonce (const UA_SecurityPolicy * sp, - UA_ByteString * out) { - UA_Int32 rc = RAND_bytes(out->data, (int) out->length); - if (rc != 1) { - return UA_STATUSCODE_BADUNEXPECTEDERROR; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(mbedErr) { +#if UA_LOGLEVEL <= 400 + char buff[100]; + int len = mbedtls_x509_crt_verify_info(buff, 100, "", flags); + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SECURITYPOLICY, + "Verifying the certificate failed with error: %.*s", len-1, buff); +#endif + if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) { + retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE || + flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) { + retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; + } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED || + flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) { + retval = UA_STATUSCODE_BADCERTIFICATEREVOKED; + } else { + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } } - return UA_STATUSCODE_GOOD; -} -static UA_StatusCode -UA_Sym_Basic128Rsa15_generateKey (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * secret, - const UA_ByteString * seed, - UA_ByteString * out) { - return UA_Openssl_Random_Key_PSHA1_Derive (secret, seed, out); + mbedtls_x509_crt_free(&remoteCertificate); + return retval; } -static size_t -UA_SymEn_Basic128Rsa15_getLocalKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - /* 16 bytes 128 bits */ - return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH; -} +static UA_StatusCode +certificateVerification_verifyApplicationURI(void *verificationContext, + const UA_ByteString *certificate, + const UA_String *applicationURI) { + CertInfo *ci = (CertInfo*)verificationContext; + if(!ci) + return UA_STATUSCODE_BADINTERNALERROR; -static size_t -UA_SymEn_Basic128Rsa15_getBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE; -} + /* Parse the certificate */ + mbedtls_x509_crt remoteCertificate; + mbedtls_x509_crt_init(&remoteCertificate); + int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data, + certificate->length); + if(mbedErr) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; -static size_t -UA_SymEn_Basic128Rsa15_getRemoteKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH; -} + /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields + * of the Alternative Subject Name. Instead test whether the URI-string is + * present in the v3_ext field in general. + * + * TODO: Improve parsing of the Alternative Subject Name */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(UA_Bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len, + applicationURI->data, applicationURI->length) == NULL) + retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID; -static size_t -UA_SymEn_Basic128Rsa15_getPlainTextBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE; + mbedtls_x509_crt_free(&remoteCertificate); + return retval; } -static UA_StatusCode -UA_SymEn_Basic128Rsa15_Encrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if(securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - return UA_OpenSSL_AES_128_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data); +static void +certificateVerification_clear(UA_CertificateVerification *cv) { + CertInfo *ci = (CertInfo*)cv->context; + if(!ci) + return; + mbedtls_x509_crt_free(&ci->certificateTrustList); + mbedtls_x509_crl_free(&ci->certificateRevocationList); + mbedtls_x509_crt_free(&ci->certificateIssuerList); + UA_String_clear(&ci->trustListFolder); + UA_String_clear(&ci->issuerListFolder); + UA_String_clear(&ci->revocationListFolder); + UA_free(ci); + cv->context = NULL; } -static UA_StatusCode -UA_SymEn_Basic128Rsa15_Decrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if(securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - return UA_OpenSSL_AES_128_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data); -} +UA_StatusCode +UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv, + const UA_ByteString *certificateTrustList, + size_t certificateTrustListSize, + const UA_ByteString *certificateIssuerList, + size_t certificateIssuerListSize, + const UA_ByteString *certificateRevocationList, + size_t certificateRevocationListSize) { + CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo)); + if(!ci) + return UA_STATUSCODE_BADOUTOFMEMORY; + memset(ci, 0, sizeof(CertInfo)); + mbedtls_x509_crt_init(&ci->certificateTrustList); + mbedtls_x509_crl_init(&ci->certificateRevocationList); + mbedtls_x509_crt_init(&ci->certificateIssuerList); -static size_t -UA_SymSig_Basic128Rsa15_getKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH; -} + cv->context = (void*)ci; + if(certificateTrustListSize > 0) + cv->verifyCertificate = certificateVerification_verify; + else + cv->verifyCertificate = certificateVerification_allow; + cv->clear = certificateVerification_clear; + cv->verifyApplicationURI = certificateVerification_verifyApplicationURI; -static size_t -UA_SymSig_Basic128Rsa15_getSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SHA1_LENGTH; -} + int err; + UA_ByteString data; + UA_ByteString_init(&data); -static UA_StatusCode -UA_SymSig_Basic128Rsa15_Verify (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - const UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - return UA_OpenSSL_HMAC_SHA1_Verify (message, - &cc->remoteSymSigningKey, - signature); -} + for(size_t i = 0; i < certificateTrustListSize; i++) { + data = copyDataFormatAware(&certificateTrustList[i]); + err = mbedtls_x509_crt_parse(&ci->certificateTrustList, + data.data, + data.length); + UA_ByteString_clear(&data); + if(err) + goto error; + } + for(size_t i = 0; i < certificateIssuerListSize; i++) { + data = copyDataFormatAware(&certificateIssuerList[i]); + err = mbedtls_x509_crt_parse(&ci->certificateIssuerList, + data.data, + data.length); + UA_ByteString_clear(&data); + if(err) + goto error; + } + for(size_t i = 0; i < certificateRevocationListSize; i++) { + data = copyDataFormatAware(&certificateRevocationList[i]); + err = mbedtls_x509_crl_parse(&ci->certificateRevocationList, + data.data, + data.length); + UA_ByteString_clear(&data); + if(err) + goto error; + } -static UA_StatusCode -UA_SymSig_Basic128Rsa15_Sign (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext; - return UA_OpenSSL_HMAC_SHA1_Sign (message, &cc->localSymSigningKey, signature); + return UA_STATUSCODE_GOOD; +error: + certificateVerification_clear(cv); + return UA_STATUSCODE_BADINTERNALERROR; } -/* the main entry of Basic128Rsa15 */ +#ifdef __linux__ /* Linux only so far */ UA_StatusCode -UA_SecurityPolicy_Basic128Rsa15 (UA_SecurityPolicy * policy, - const UA_ByteString localCertificate, - const UA_ByteString localPrivateKey, - const UA_Logger * logger) { +UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv, + const char *trustListFolder, + const char *issuerListFolder, + const char *revocationListFolder) { + CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo)); + if(!ci) + return UA_STATUSCODE_BADOUTOFMEMORY; + memset(ci, 0, sizeof(CertInfo)); + mbedtls_x509_crt_init(&ci->certificateTrustList); + mbedtls_x509_crl_init(&ci->certificateRevocationList); + mbedtls_x509_crt_init(&ci->certificateIssuerList); - UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; - UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; - UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; - UA_StatusCode retval; + /* Only set the folder paths. They will be reloaded during runtime. + * TODO: Add a more efficient reloading of only the changes */ + ci->trustListFolder = UA_STRING_ALLOC(trustListFolder); + ci->issuerListFolder = UA_STRING_ALLOC(issuerListFolder); + ci->revocationListFolder = UA_STRING_ALLOC(revocationListFolder); - UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY, - "The Basic128Rsa15 security policy with openssl is added."); + reloadCertificates(ci); - UA_Openssl_Init (); - memset(policy, 0, sizeof(UA_SecurityPolicy)); - policy->logger = logger; - policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15\0"); + cv->context = (void*)ci; + cv->verifyCertificate = certificateVerification_verify; + cv->clear = certificateVerification_clear; + cv->verifyApplicationURI = certificateVerification_verifyApplicationURI; - /* set ChannelModule context */ + return UA_STATUSCODE_GOOD; +} - channelModule->newContext = UA_ChannelModule_Basic128Rsa15_New_Context; - channelModule->deleteContext = UA_ChannelModule_Basic128Rsa15_Delete_Context; +#endif +#endif - channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic128Rsa15_setLocalSymSigningKey; - channelModule->setLocalSymEncryptingKey = UA_ChannelModule_Basic128Rsa15_setLocalSymEncryptingKey; - channelModule->setLocalSymIv = UA_ChannelModule_Basic128Rsa15_setLocalSymIv; - channelModule->setRemoteSymSigningKey = UA_ChannelModule_Basic128Rsa15_setRemoteSymSigningKey; - channelModule->setRemoteSymEncryptingKey = UA_ChannelModule_Basic128Rsa15_setRemoteSymEncryptingKey; - channelModule->setRemoteSymIv = UA_ChannelModule_Basic128Rsa15_setRemoteSymIv; - channelModule->compareCertificate = UA_ChannelModule_Basic128Rsa15_compareCertificate; +/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_mbedtls_common.c" ****/ - retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); - if (retval != UA_STATUSCODE_GOOD) - return retval; +#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS) || defined(UA_ENABLE_PUBSUB_ENCRYPTION) - /* asymmetricModule */ - asymmetricModule->compareCertificateThumbprint = UA_Asy_Basic128Rsa15_compareCertificateThumbprint; - asymmetricModule->makeCertificateThumbprint = UA_Asy_Basic128Rsa15_makeCertificateThumbprint; +#include <mbedtls/aes.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/entropy.h> +#include <mbedtls/error.h> +#include <mbedtls/md.h> +#include <mbedtls/sha1.h> +#include <mbedtls/version.h> +#include <mbedtls/x509_crt.h> - /* AsymmetricModule - signature algorithm */ +void +swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) { + UA_ByteString tmp = *bufA; + *bufA = *bufB; + *bufB = tmp; +} - UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm = - &asymmetricModule->cryptoModule.signatureAlgorithm; - asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); - asySigAlgorithm->getRemoteSignatureSize = UA_AsySig_Basic128Rsa15_getRemoteSignatureSize; - asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic128Rsa15_getLocalSignatureSize; - asySigAlgorithm->getLocalKeyLength = NULL; - asySigAlgorithm->getRemoteKeyLength = NULL; - asySigAlgorithm->verify = UA_AsySig_Basic128Rsa15_Verify; - asySigAlgorithm->sign = UA_AsySig_Basic128Rsa15_Sign; +void +mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key, + const UA_ByteString *in, unsigned char *out) { + mbedtls_md_hmac_starts(context, key->data, key->length); + mbedtls_md_hmac_update(context, in->data, in->length); + mbedtls_md_hmac_finish(context, out); +} - /* AsymmetricModule encryption algorithm */ +UA_StatusCode +mbedtls_generateKey(mbedtls_md_context_t *context, + const UA_ByteString *secret, const UA_ByteString *seed, + UA_ByteString *out) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + size_t hashLen = (size_t)mbedtls_md_get_size(context->md_info); +#else + size_t hashLen = (size_t)mbedtls_md_get_size(context->private_md_info); +#endif - UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg = - &asymmetricModule->cryptoModule.encryptionAlgorithm; - asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5\0"); - asymEncryAlg->getRemotePlainTextBlockSize = UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize; - asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic128Rsa15_getRemoteBlockSize; - asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic128Rsa15_getRemoteKeyLength; - asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic128Rsa15_getLocalKeyLength; - asymEncryAlg->getLocalPlainTextBlockSize = NULL; - asymEncryAlg->getLocalBlockSize = NULL; - asymEncryAlg->decrypt = UA_AsymEn_Basic128Rsa15_Decrypt; - asymEncryAlg->encrypt = UA_AsymEn_Basic128Rsa15_Encrypt; + UA_ByteString A_and_seed; + UA_ByteString_allocBuffer(&A_and_seed, hashLen + seed->length); + memcpy(A_and_seed.data + hashLen, seed->data, seed->length); - /* SymmetricModule */ + UA_ByteString ANext_and_seed; + UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length); + memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length); - symmetricModule->secureChannelNonceLength = 16; /* 128 bits*/ - symmetricModule->generateNonce = UA_Sym_Basic128Rsa15_generateNonce; - symmetricModule->generateKey = UA_Sym_Basic128Rsa15_generateKey; + UA_ByteString A = { + hashLen, + A_and_seed.data + }; - /* Symmetric encryption Algorithm */ + UA_ByteString ANext = { + hashLen, + ANext_and_seed.data + }; - UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm = - &symmetricModule->cryptoModule.encryptionAlgorithm; - symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0"); - symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic128Rsa15_getLocalKeyLength; - symEncryptionAlgorithm->getLocalBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize; - symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic128Rsa15_getRemoteKeyLength; - symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize; - symEncryptionAlgorithm->getLocalPlainTextBlockSize = UA_SymEn_Basic128Rsa15_getPlainTextBlockSize; - symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic128Rsa15_getPlainTextBlockSize; - symEncryptionAlgorithm->decrypt = UA_SymEn_Basic128Rsa15_Decrypt; - symEncryptionAlgorithm->encrypt = UA_SymEn_Basic128Rsa15_Encrypt; + mbedtls_hmac(context, secret, seed, A.data); - /* Symmetric signature Algorithm */ + UA_StatusCode retval = 0; + for(size_t offset = 0; offset < out->length; offset += hashLen) { + UA_ByteString outSegment = { + hashLen, + out->data + offset + }; + UA_Boolean bufferAllocated = UA_FALSE; + // Not enough room in out buffer to write the hash. + if(offset + hashLen > out->length) { + outSegment.data = NULL; + outSegment.length = 0; + retval = UA_ByteString_allocBuffer(&outSegment, hashLen); + if(retval != UA_STATUSCODE_GOOD) { + UA_ByteString_clear(&A_and_seed); + UA_ByteString_clear(&ANext_and_seed); + return retval; + } + bufferAllocated = UA_TRUE; + } - UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm = - &symmetricModule->cryptoModule.signatureAlgorithm; - symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); - symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength; - symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength; - symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize; - symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize; + mbedtls_hmac(context, secret, &A_and_seed, outSegment.data); + mbedtls_hmac(context, secret, &A, ANext.data); - symSignatureAlgorithm->verify = UA_SymSig_Basic128Rsa15_Verify; - symSignatureAlgorithm->sign = UA_SymSig_Basic128Rsa15_Sign; + if(retval != UA_STATUSCODE_GOOD) { + if(bufferAllocated) + UA_ByteString_clear(&outSegment); + UA_ByteString_clear(&A_and_seed); + UA_ByteString_clear(&ANext_and_seed); + return retval; + } - /* set the policy context */ + if(bufferAllocated) { + memcpy(out->data + offset, outSegment.data, out->length - offset); + UA_ByteString_clear(&outSegment); + } - retval = UA_Policy_Basic128Rsa15_New_Context (policy, localPrivateKey, logger); - if (retval != UA_STATUSCODE_GOOD) { - UA_ByteString_clear (&policy->localCertificate); - return retval; + swapBuffers(&ANext_and_seed, &A_and_seed); + swapBuffers(&ANext, &A); } - policy->clear = UA_Policy_Basic128Rsa15_Clear_Context; - - /* Use the same signature algorithm as the asymmetric component for - certificate signing (see standard) */ - policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + UA_ByteString_clear(&A_and_seed); + UA_ByteString_clear(&ANext_and_seed); return UA_STATUSCODE_GOOD; } +UA_StatusCode +mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message, + const UA_ByteString *signature) { + /* Compute the sha1 hash */ + unsigned char hash[UA_SHA1_LENGTH]; +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_sha1_ret(message->data, message->length, hash); +#else + mbedtls_sha1(message->data, message->length, hash); #endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/openssl/ua_openssl_basic256.c" ***********************************/ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright 2020 (c) Wind River Systems, Inc. - * Copyright 2020 (c) basysKom GmbH - */ + /* Set the RSA settings */ + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(certificate->pk); + if(!rsaContext) + return UA_STATUSCODE_BADINTERNALERROR; + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); -/* -modification history --------------------- -12mar20,lan written -*/ + /* Verify */ + int mbedErr = mbedtls_pk_verify(&certificate->pk, + MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH, + signature->data, signature->length); + if(mbedErr) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + return UA_STATUSCODE_GOOD; +} +UA_StatusCode +mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey, + mbedtls_ctr_drbg_context *drbgContext, + const UA_ByteString *message, + UA_ByteString *signature) { + unsigned char hash[UA_SHA1_LENGTH]; +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_sha1_ret(message->data, message->length, hash); +#else + mbedtls_sha1(message->data, message->length, hash); +#endif -#ifdef UA_ENABLE_ENCRYPTION_OPENSSL + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey); + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); + size_t sigLen = 0; + int mbedErr = mbedtls_pk_sign(localPrivateKey, MBEDTLS_MD_SHA1, hash, + UA_SHA1_LENGTH, signature->data, +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + signature->length, +#endif + &sigLen, + mbedtls_ctr_drbg_random, drbgContext); + if(mbedErr) + return UA_STATUSCODE_BADINTERNALERROR; + return UA_STATUSCODE_GOOD; +} -#include <openssl/x509.h> -#include <openssl/rand.h> +UA_StatusCode +mbedtls_thumbprint_sha1(const UA_ByteString *certificate, + UA_ByteString *thumbprint) { + if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL)) + return UA_STATUSCODE_BADINTERNALERROR; -#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN 42 -#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH 32 -#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE 16 -#define UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE 16 -#define UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH 24 -#define UA_SHA1_LENGTH 20 + if(thumbprint->length != UA_SHA1_LENGTH) + return UA_STATUSCODE_BADINTERNALERROR; -typedef struct { - EVP_PKEY * localPrivateKey; - UA_ByteString localCertThumbprint; - const UA_Logger * logger; -} Policy_Context_Basic256; + /* The certificate thumbprint is always a 20 bit sha1 hash, see Part 4 of the Specification. */ +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + mbedtls_sha1_ret(certificate->data, certificate->length, thumbprint->data); +#else + mbedtls_sha1(certificate->data, certificate->length, thumbprint->data); +#endif + return UA_STATUSCODE_GOOD; +} -typedef struct { - UA_ByteString localSymSigningKey; - UA_ByteString localSymEncryptingKey; - UA_ByteString localSymIv; - UA_ByteString remoteSymSigningKey; - UA_ByteString remoteSymEncryptingKey; - UA_ByteString remoteSymIv; +UA_StatusCode +mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context, + mbedtls_ctr_drbg_context *drbgContext, + UA_ByteString *data, const size_t plainTextBlockSize) { + if(data->length % plainTextBlockSize != 0) + return UA_STATUSCODE_BADINTERNALERROR; - Policy_Context_Basic256 * policyContext; - UA_ByteString remoteCertificate; - X509 * remoteCertificateX509; -} Channel_Context_Basic256; + size_t max_blocks = data->length / plainTextBlockSize; -static UA_StatusCode -UA_Policy_Basic256_New_Context (UA_SecurityPolicy * securityPolicy, - const UA_ByteString localPrivateKey, - const UA_Logger * logger) { - Policy_Context_Basic256 * context = (Policy_Context_Basic256 *) - UA_malloc (sizeof (Policy_Context_Basic256)); - if (context == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } - - context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); - if (!context->localPrivateKey) { - UA_free (context); - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + UA_ByteString encrypted; +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * context->len); +#else + size_t keylen = mbedtls_rsa_get_len(context); + UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * keylen); - UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint ( - &securityPolicy->localCertificate, - &context->localCertThumbprint, true - ); - if (retval != UA_STATUSCODE_GOOD) { - EVP_PKEY_free(context->localPrivateKey); - UA_free (context); - return retval; - } +#endif - context->logger = logger; - securityPolicy->policyContext = context; + if(retval != UA_STATUSCODE_GOOD) + return retval; - return UA_STATUSCODE_GOOD; -} + size_t lenDataToEncrypt = data->length; + size_t inOffset = 0; + size_t offset = 0; + const unsigned char *label = NULL; + while(lenDataToEncrypt >= plainTextBlockSize) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random, + drbgContext, MBEDTLS_RSA_PUBLIC, + label, 0, plainTextBlockSize, + data->data + inOffset, encrypted.data + offset); +#else + int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random, + drbgContext, label, 0, plainTextBlockSize, + data->data + inOffset, encrypted.data + offset); +#endif -static void -UA_Policy_Basic256_Clear_Context (UA_SecurityPolicy *policy) { - if (policy == NULL) { - return; - } - UA_ByteString_deleteMembers(&policy->localCertificate); + if(mbedErr) { + UA_ByteString_clear(&encrypted); + return UA_STATUSCODE_BADINTERNALERROR; + } - Policy_Context_Basic256 * ctx = (Policy_Context_Basic256 *) policy->policyContext; - if (ctx == NULL) { - return; + inOffset += plainTextBlockSize; +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + offset += context->len; +#else + offset += keylen; +#endif + lenDataToEncrypt -= plainTextBlockSize; } - /* delete all allocated members in the context */ - - EVP_PKEY_free(ctx->localPrivateKey); - UA_ByteString_deleteMembers (&ctx->localCertThumbprint); - UA_free (ctx); - - return; + memcpy(data->data, encrypted.data, offset); + UA_ByteString_clear(&encrypted); + return UA_STATUSCODE_GOOD; } -/* create the channel context */ +UA_StatusCode +mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey, + mbedtls_ctr_drbg_context *drbgContext, + UA_ByteString *data) { + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey); + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + if(data->length % rsaContext->len != 0) + return UA_STATUSCODE_BADINTERNALERROR; +#else + size_t keylen = mbedtls_rsa_get_len(rsaContext); + if(data->length % keylen != 0) + return UA_STATUSCODE_BADINTERNALERROR; +#endif -static UA_StatusCode -UA_ChannelModule_Basic256_New_Context (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * remoteCertificate, - void ** channelContext) { - if (securityPolicy == NULL || remoteCertificate == NULL || - channelContext == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - Channel_Context_Basic256 * context = (Channel_Context_Basic256 *) - UA_malloc (sizeof (Channel_Context_Basic256)); - if (context == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } + size_t inOffset = 0; + size_t outOffset = 0; + size_t outLength = 0; + unsigned char buf[512]; - UA_ByteString_init(&context->localSymSigningKey); - UA_ByteString_init(&context->localSymEncryptingKey); - UA_ByteString_init(&context->localSymIv); - UA_ByteString_init(&context->remoteSymSigningKey); - UA_ByteString_init(&context->remoteSymEncryptingKey); - UA_ByteString_init(&context->remoteSymIv); + while(inOffset < data->length) { +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random, + drbgContext, MBEDTLS_RSA_PRIVATE, + NULL, 0, &outLength, + data->data + inOffset, + buf, 512); +#else + int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random, + drbgContext, + NULL, 0, &outLength, + data->data + inOffset, + buf, 512); +#endif - UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate, - remoteCertificate); - if (retval != UA_STATUSCODE_GOOD) { - UA_free (context); - return retval; - } + if(mbedErr) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - /* decode to X509 */ - context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); - if (context->remoteCertificateX509 == NULL) { - UA_ByteString_clear (&context->remoteCertificate); - UA_free (context); - return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; + memcpy(data->data + outOffset, buf, outLength); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + inOffset += rsaContext->len; +#else + inOffset += keylen; +#endif + outOffset += outLength; } - context->policyContext = (Policy_Context_Basic256 *) - (securityPolicy->policyContext); + data->length = outOffset; + return UA_STATUSCODE_GOOD; +} - *channelContext = context; +int +UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target, void *p_rng) { + UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(key); +#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000 + int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0); +#else + int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0, mbedtls_entropy_func, p_rng); +#endif + UA_ByteString_clear(&data); + return mbedErr; +} - UA_LOG_INFO (securityPolicy->logger, - UA_LOGCATEGORY_SECURITYPOLICY, - "The basic256 security policy channel with openssl is created."); +UA_StatusCode +UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData, + UA_ByteString *target) { + UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(certData); - return UA_STATUSCODE_GOOD; -} + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); -/* delete the channel context */ + int mbedErr = mbedtls_x509_crt_parse(&cert, data.data, data.length); -static void -UA_ChannelModule_Basic256_Delete_Context (void * channelContext) { - if (channelContext != NULL) { - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) - channelContext; - X509_free (cc->remoteCertificateX509); - UA_ByteString_deleteMembers (&cc->remoteCertificate); - UA_ByteString_deleteMembers (&cc->localSymSigningKey); - UA_ByteString_deleteMembers (&cc->localSymEncryptingKey); - UA_ByteString_deleteMembers (&cc->localSymIv); - UA_ByteString_deleteMembers (&cc->remoteSymSigningKey); - UA_ByteString_deleteMembers (&cc->remoteSymEncryptingKey); - UA_ByteString_deleteMembers (&cc->remoteSymIv); - UA_LOG_INFO (cc->policyContext->logger, - UA_LOGCATEGORY_SECURITYPOLICY, - "The basic256 security policy channel with openssl is deleted."); + UA_StatusCode result = UA_STATUSCODE_BADINVALIDARGUMENT; - UA_free (cc); + if (!mbedErr) { + UA_ByteString tmp; + tmp.data = cert.raw.p; + tmp.length = cert.raw.len; + + result = UA_ByteString_copy(&tmp, target); + } else { + UA_ByteString_init(target); } + + UA_ByteString_clear(&data); + mbedtls_x509_crt_free(&cert); + return result; } -/* Compares the supplied certificate with the certificate - * in the endpoit context - */ +// mbedTLS expects PEM data to be null terminated +// The data length parameter must include the null terminator +UA_ByteString +UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data) { + UA_ByteString result; + UA_ByteString_init(&result); -static UA_StatusCode -UA_Asy_Basic256_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * certificateThumbprint) { - if (securityPolicy == NULL || certificateThumbprint == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } - Policy_Context_Basic256 *pc = (Policy_Context_Basic256 *) - securityPolicy->policyContext; - if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) { - return UA_STATUSCODE_BADCERTIFICATEINVALID; + if (!data->length) + return result; + + if (data->length && data->data[0] == '-') { + UA_ByteString_allocBuffer(&result, data->length + 1); + memcpy(result.data, data->data, data->length); + result.data[data->length] = '\0'; + } else { + UA_ByteString_copy(data, &result); } - return UA_STATUSCODE_GOOD; + + return result; } -/* Generates a thumbprint for the specified certificate */ +#endif -static UA_StatusCode -UA_Asy_Basic256_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * certificate, - UA_ByteString * thumbprint) { - return UA_Openssl_X509_GetCertificateThumbprint (certificate, - thumbprint, false); -} +/**** amalgamated original file "/plugins/ua_log_stdout.c" ****/ -static UA_StatusCode -UA_ChannelModule_Basic256_setLocalSymSigningKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2016-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + */ - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymSigningKey); - return UA_ByteString_copy(key, &cc->localSymSigningKey); -} -static UA_StatusCode -UA_ChannelModule_Basic256_setLocalSymEncryptingKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +#include <stdio.h> - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); - return UA_ByteString_copy(key, &cc->localSymEncryptingKey); -} +#if UA_MULTITHREADING >= 100 +#include <pthread.h> +static pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif -static UA_StatusCode -UA_ChannelModule_Basic256_setLocalSymIv (void * channelContext, - const UA_ByteString * iv) { - if (iv == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +/* ANSI escape sequences for color output taken from here: + * https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c*/ - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymIv); - return UA_ByteString_copy(iv, &cc->localSymIv); -} +#ifdef UA_ENABLE_LOG_COLORS +# define ANSI_COLOR_RED "\x1b[31m" +# define ANSI_COLOR_GREEN "\x1b[32m" +# define ANSI_COLOR_YELLOW "\x1b[33m" +# define ANSI_COLOR_BLUE "\x1b[34m" +# define ANSI_COLOR_MAGENTA "\x1b[35m" +# define ANSI_COLOR_CYAN "\x1b[36m" +# define ANSI_COLOR_RESET "\x1b[0m" +#else +# define ANSI_COLOR_RED "" +# define ANSI_COLOR_GREEN "" +# define ANSI_COLOR_YELLOW "" +# define ANSI_COLOR_BLUE "" +# define ANSI_COLOR_MAGENTA "" +# define ANSI_COLOR_CYAN "" +# define ANSI_COLOR_RESET "" +#endif -static UA_StatusCode -UA_ChannelModule_Basic256_setRemoteSymSigningKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +const char *logLevelNames[6] = {"trace", "debug", + ANSI_COLOR_GREEN "info", + ANSI_COLOR_YELLOW "warn", + ANSI_COLOR_RED "error", + ANSI_COLOR_MAGENTA "fatal"}; +const char *logCategoryNames[7] = {"network", "channel", "session", "server", + "client", "userland", "securitypolicy"}; - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); - return UA_ByteString_copy(key, &cc->remoteSymSigningKey); -} +#ifdef __clang__ +__attribute__((__format__(__printf__, 4 , 0))) +#endif +void +UA_Log_Stdout_log(void *context, UA_LogLevel level, UA_LogCategory category, + const char *msg, va_list args) { -static UA_StatusCode -UA_ChannelModule_Basic256_setRemoteSymEncryptingKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* Assume that context is casted to UA_LogLevel */ + /* TODO we may later change this to a struct with bitfields to filter on category */ + if ( context != NULL && (UA_LogLevel)(uintptr_t)context > level ) + return; - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); - return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); -} + UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset(); + UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset); -static UA_StatusCode -UA_ChannelModule_Basic256_setRemoteSymIv (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +#if UA_MULTITHREADING >= 100 + pthread_mutex_lock(&printf_mutex); +#endif - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymIv); - return UA_ByteString_copy(key, &cc->remoteSymIv); + printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t", + dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec, + (int)(tOffset / UA_DATETIME_SEC / 36), logLevelNames[level], logCategoryNames[category]); + vprintf(msg, args); + printf("\n"); + fflush(stdout); + +#if UA_MULTITHREADING >= 100 + pthread_mutex_unlock(&printf_mutex); +#endif } -static UA_StatusCode -UA_ChannelModule_Basic256_compareCertificate (const void * channelContext, - const UA_ByteString * certificate) { - if(channelContext == NULL || certificate == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +void +UA_Log_Stdout_clear(void *logContext) { - const Channel_Context_Basic256 * cc = - (const Channel_Context_Basic256 *) channelContext; - return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509); } -static size_t -UA_AsySig_Basic256_getRemoteSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +const UA_Logger UA_Log_Stdout_ = {UA_Log_Stdout_log, NULL, UA_Log_Stdout_clear}; +const UA_Logger *UA_Log_Stdout = &UA_Log_Stdout_; - const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen; +/* By default the client and server is configured with UA_Log_Stdout + This constructs a logger with a configurable max log level */ + +UA_Logger UA_Log_Stdout_withLevel(UA_LogLevel minlevel) +{ + UA_Logger logger = {UA_Log_Stdout_log, (void*)minlevel, UA_Log_Stdout_clear}; + return logger; } -static size_t -UA_AsySig_Basic256_getLocalSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +/**** amalgamated original file "/plugins/ua_accesscontrol_default.c" ****/ - Policy_Context_Basic256 * pc = - (Policy_Context_Basic256 *) securityPolicy->policyContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ - return (size_t) keyLen; -} -static UA_StatusCode -UA_AsySig_Basic256_Verify (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - const UA_ByteString * signature) { - if (securityPolicy == NULL || message == NULL || signature == NULL || - channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +/* Example access control management. Anonymous and username / password login. + * The access rights are maximally permissive. + * + * FOR PRODUCTION USE, THIS EXAMPLE PLUGIN SHOULD BE REPLACED WITH LESS + * PERMISSIVE ACCESS CONTROL. + * + * For TransferSubscriptions, we check whether the transfer happens between + * Sessions for the same user. */ - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (message, - cc->remoteCertificateX509, signature); +typedef struct { + UA_Boolean allowAnonymous; + size_t usernamePasswordLoginSize; + UA_UsernamePasswordLogin *usernamePasswordLogin; + UA_CertificateVerification verifyX509; +} AccessControlContext; - return retval; -} +#define ANONYMOUS_POLICY "open62541-anonymous-policy" +#define CERTIFICATE_POLICY "open62541-certificate-policy" +#define USERNAME_POLICY "open62541-username-policy" +const UA_String anonymous_policy = UA_STRING_STATIC(ANONYMOUS_POLICY); +const UA_String certificate_policy = UA_STRING_STATIC(CERTIFICATE_POLICY); +const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY); + +/************************/ +/* Access Control Logic */ +/************************/ static UA_StatusCode -UA_AsySig_Basic256_Sign (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +activateSession_default(UA_Server *server, UA_AccessControl *ac, + const UA_EndpointDescription *endpointDescription, + const UA_ByteString *secureChannelRemoteCertificate, + const UA_NodeId *sessionId, + const UA_ExtensionObject *userIdentityToken, + void **sessionContext) { + AccessControlContext *context = (AccessControlContext*)ac->context; - Policy_Context_Basic256 * pc = - (Policy_Context_Basic256 *) securityPolicy->policyContext; - return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (message, pc->localPrivateKey, - signature); -} + /* The empty token is interpreted as anonymous */ + if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { + if(!context->allowAnonymous) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; -static size_t -UA_AsymEn_Basic256_getRemotePlainTextBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* No userdata atm */ + *sessionContext = NULL; + return UA_STATUSCODE_GOOD; } - const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN; -} + /* Could the token be decoded? */ + if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; -static size_t -UA_AsymEn_Basic256_getRemoteBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* Anonymous login */ + if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) { + if(!context->allowAnonymous) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; - const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen; -} + const UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*) + userIdentityToken->content.decoded.data; -static size_t -UA_AsymEn_Basic256_getRemoteKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* Compatibility notice: Siemens OPC Scout v10 provides an empty + * policyId. This is not compliant. For compatibility, assume that empty + * policyId == ANONYMOUS_POLICY */ + if(token->policyId.data && !UA_String_equal(&token->policyId, &anonymous_policy)) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; - const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen * 8; -} + /* No userdata atm */ + *sessionContext = NULL; + return UA_STATUSCODE_GOOD; + } -static size_t -UA_AsymEn_Basic256_getLocalKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* Username and password */ + if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) { + const UA_UserNameIdentityToken *userToken = + (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data; - Policy_Context_Basic256 * pc = - (Policy_Context_Basic256 *) securityPolicy->policyContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); + if(!UA_String_equal(&userToken->policyId, &username_policy)) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; - return (size_t) keyLen * 8; -} + /* The userToken has been decrypted by the server before forwarding + * it to the plugin. This information can be used here. */ + /* if(userToken->encryptionAlgorithm.length > 0) {} */ -static UA_StatusCode -UA_AsymEn_Basic256_Decrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if (securityPolicy == NULL || channelContext == NULL || data == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } + /* Empty username and password */ + if(userToken->userName.length == 0 && userToken->password.length == 0) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - UA_StatusCode ret = UA_Openssl_RSA_Oaep_Decrypt (data, - cc->policyContext->localPrivateKey); - return ret; -} + /* Try to match username/pw */ + UA_Boolean match = false; + for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) { + if(UA_String_equal(&userToken->userName, &context->usernamePasswordLogin[i].username) && + UA_String_equal(&userToken->password, &context->usernamePasswordLogin[i].password)) { + match = true; + break; + } + } + if(!match) + return UA_STATUSCODE_BADUSERACCESSDENIED; -static UA_StatusCode -UA_AsymEn_Basic256_Encrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if (securityPolicy == NULL || channelContext == NULL || - data == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; + /* For the CTT, recognize whether two sessions are */ + UA_ByteString *username = UA_ByteString_new(); + if(username) + UA_ByteString_copy(&userToken->userName, username); + *sessionContext = username; + return UA_STATUSCODE_GOOD; } - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - return UA_Openssl_RSA_OAEP_Encrypt (data, UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN, - cc->remoteCertificateX509); -} + /* x509 certificate */ + if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) { + const UA_X509IdentityToken *userToken = (UA_X509IdentityToken*) + userIdentityToken->content.decoded.data; -static UA_StatusCode -UA_Sym_Basic256_generateNonce (const UA_SecurityPolicy * sp, - UA_ByteString * out) { - UA_Int32 rc = RAND_bytes(out->data, (int) out->length); - if (rc != 1) { - return UA_STATUSCODE_BADUNEXPECTEDERROR; + if(!UA_String_equal(&userToken->policyId, &certificate_policy)) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + if(!context->verifyX509.verifyCertificate) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + return context->verifyX509. + verifyCertificate(context->verifyX509.context, + &userToken->certificateData); } - return UA_STATUSCODE_GOOD; -} -static UA_StatusCode -UA_Sym_Basic256_generateKey (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * secret, - const UA_ByteString * seed, - UA_ByteString * out) { - return UA_Openssl_Random_Key_PSHA1_Derive (secret, seed, out); + /* Unsupported token type */ + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; } -static size_t -UA_SymEn_Basic256_getLocalKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - /* 32 bytes 256 bits */ - return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH; +static void +closeSession_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext) { + if(sessionContext) + UA_ByteString_delete((UA_ByteString*)sessionContext); } -static size_t -UA_SymEn_Basic256_getBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE; +static UA_UInt32 +getUserRightsMask_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext) { + return 0xFFFFFFFF; } -static size_t -UA_SymEn_Basic256_getRemoteKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - /* 32 bytes 256 bits */ - return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH; +static UA_Byte +getUserAccessLevel_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext) { + return 0xFF; } -static size_t -UA_SymEn_Basic256_getPlainTextBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE; +static UA_Boolean +getUserExecutable_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext) { + return true; } -static UA_StatusCode -UA_SymEn_Basic256_Encrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if(securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - return UA_OpenSSL_AES_256_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data); +static UA_Boolean +getUserExecutableOnObject_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *methodId, void *methodContext, + const UA_NodeId *objectId, void *objectContext) { + return true; } -static UA_StatusCode -UA_SymEn_Basic256_Decrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if(securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - return UA_OpenSSL_AES_256_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data); +static UA_Boolean +allowAddNode_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddNodesItem *item) { + return true; } -static size_t -UA_SymSig_Basic256_getKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH; +static UA_Boolean +allowAddReference_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddReferencesItem *item) { + return true; } -static size_t -UA_SymSig_Basic256_getSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SHA1_LENGTH; +static UA_Boolean +allowDeleteNode_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteNodesItem *item) { + return true; } -static UA_StatusCode -UA_SymSig_Basic256_Verify (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - const UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - return UA_OpenSSL_HMAC_SHA1_Verify (message, - &cc->remoteSymSigningKey, - signature); +static UA_Boolean +allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteReferencesItem *item) { + return true; } -static UA_StatusCode -UA_SymSig_Basic256_Sign (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; - - Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext; - return UA_OpenSSL_HMAC_SHA1_Sign (message, &cc->localSymSigningKey, signature); +static UA_Boolean +allowBrowseNode_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext) { + return true; } -/* the main entry of Basic256 */ - -UA_StatusCode -UA_SecurityPolicy_Basic256 (UA_SecurityPolicy * policy, - const UA_ByteString localCertificate, - const UA_ByteString localPrivateKey, - const UA_Logger * logger) { - UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; - UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; - UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; - UA_StatusCode retval; - - UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY, - "The basic256 security policy with openssl is added."); - - UA_Openssl_Init (); - memset(policy, 0, sizeof(UA_SecurityPolicy)); - policy->logger = logger; - policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256\0"); +#ifdef UA_ENABLE_SUBSCRIPTIONS +static UA_Boolean +allowTransferSubscription_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *oldSessionId, void *oldSessionContext, + const UA_NodeId *newSessionId, void *newSessionContext) { + if(oldSessionContext == newSessionContext) + return true; + if(oldSessionContext && newSessionContext) + return UA_ByteString_equal((UA_ByteString*)oldSessionContext, + (UA_ByteString*)newSessionContext); + return false; +} +#endif - /* set ChannelModule context */ +#ifdef UA_ENABLE_HISTORIZING +static UA_Boolean +allowHistoryUpdateUpdateData_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, + UA_PerformUpdateType performInsertReplace, + const UA_DataValue *value) { + return true; +} - channelModule->newContext = UA_ChannelModule_Basic256_New_Context; - channelModule->deleteContext = UA_ChannelModule_Basic256_Delete_Context; +static UA_Boolean +allowHistoryUpdateDeleteRawModified_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, + UA_DateTime startTimestamp, + UA_DateTime endTimestamp, + bool isDeleteModified) { + return true; +} +#endif - channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic256_setLocalSymSigningKey; - channelModule->setLocalSymEncryptingKey = UA_ChannelModule_Basic256_setLocalSymEncryptingKey; - channelModule->setLocalSymIv = UA_ChannelModule_Basic256_setLocalSymIv; - channelModule->setRemoteSymSigningKey = UA_ChannelModule_Basic256_setRemoteSymSigningKey; - channelModule->setRemoteSymEncryptingKey = UA_ChannelModule_Basic256_setRemoteSymEncryptingKey; - channelModule->setRemoteSymIv = UA_ChannelModule_Basic256_setRemoteSymIv; - channelModule->compareCertificate = UA_ChannelModule_Basic256_compareCertificate; +/***************************************/ +/* Create Delete Access Control Plugin */ +/***************************************/ - retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); +static void clear_default(UA_AccessControl *ac) { + UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies, + ac->userTokenPoliciesSize, + &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + ac->userTokenPolicies = NULL; + ac->userTokenPoliciesSize = 0; - if (retval != UA_STATUSCODE_GOOD) - return retval; + AccessControlContext *context = (AccessControlContext*)ac->context; - /* asymmetricModule */ + if (context) { + for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) { + UA_String_clear(&context->usernamePasswordLogin[i].username); + UA_String_clear(&context->usernamePasswordLogin[i].password); + } + if(context->usernamePasswordLoginSize > 0) + UA_free(context->usernamePasswordLogin); - asymmetricModule->compareCertificateThumbprint = UA_Asy_Basic256_compareCertificateThumbprint; - asymmetricModule->makeCertificateThumbprint = UA_Asy_Basic256_makeCertificateThumbprint; + if(context->verifyX509.clear) + context->verifyX509.clear(&context->verifyX509); - /* AsymmetricModule - signature algorithm */ + UA_free(ac->context); + ac->context = NULL; + } +} - UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm = - &asymmetricModule->cryptoModule.signatureAlgorithm; - asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); - asySigAlgorithm->getRemoteSignatureSize = UA_AsySig_Basic256_getRemoteSignatureSize; - asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic256_getLocalSignatureSize; - asySigAlgorithm->verify = UA_AsySig_Basic256_Verify; - asySigAlgorithm->sign = UA_AsySig_Basic256_Sign; - asySigAlgorithm->getLocalKeyLength = NULL; - asySigAlgorithm->getRemoteKeyLength = NULL; +UA_StatusCode +UA_AccessControl_default(UA_ServerConfig *config, + UA_Boolean allowAnonymous, + UA_CertificateVerification *verifyX509, + const UA_ByteString *userTokenPolicyUri, + size_t usernamePasswordLoginSize, + const UA_UsernamePasswordLogin *usernamePasswordLogin) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_SERVER, + "AccessControl: Unconfigured AccessControl. Users have all permissions."); + UA_AccessControl *ac = &config->accessControl; - /* AsymmetricModule encryption algorithm */ + if(ac->clear) + clear_default(ac); + + ac->clear = clear_default; + ac->activateSession = activateSession_default; + ac->closeSession = closeSession_default; + ac->getUserRightsMask = getUserRightsMask_default; + ac->getUserAccessLevel = getUserAccessLevel_default; + ac->getUserExecutable = getUserExecutable_default; + ac->getUserExecutableOnObject = getUserExecutableOnObject_default; + ac->allowAddNode = allowAddNode_default; + ac->allowAddReference = allowAddReference_default; + ac->allowBrowseNode = allowBrowseNode_default; - UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg = - &asymmetricModule->cryptoModule.encryptionAlgorithm; - asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); - asymEncryAlg->getRemotePlainTextBlockSize = UA_AsymEn_Basic256_getRemotePlainTextBlockSize; - asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic256_getRemoteBlockSize; - asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic256_getRemoteKeyLength; - asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic256_getLocalKeyLength; - asymEncryAlg->getLocalPlainTextBlockSize = NULL; - asymEncryAlg->getLocalBlockSize = NULL; - asymEncryAlg->decrypt = UA_AsymEn_Basic256_Decrypt; - asymEncryAlg->encrypt = UA_AsymEn_Basic256_Encrypt; +#ifdef UA_ENABLE_SUBSCRIPTIONS + ac->allowTransferSubscription = allowTransferSubscription_default; +#endif - /* SymmetricModule */ +#ifdef UA_ENABLE_HISTORIZING + ac->allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData_default; + ac->allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified_default; +#endif - symmetricModule->secureChannelNonceLength = 32; - symmetricModule->generateNonce = UA_Sym_Basic256_generateNonce; - symmetricModule->generateKey = UA_Sym_Basic256_generateKey; + ac->allowDeleteNode = allowDeleteNode_default; + ac->allowDeleteReference = allowDeleteReference_default; - /* Symmetric encryption Algorithm */ + AccessControlContext *context = (AccessControlContext*) + UA_malloc(sizeof(AccessControlContext)); + if(!context) + return UA_STATUSCODE_BADOUTOFMEMORY; + memset(context, 0, sizeof(AccessControlContext)); + ac->context = context; - UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm = - &symmetricModule->cryptoModule.encryptionAlgorithm; - symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0"); - symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic256_getLocalKeyLength; - symEncryptionAlgorithm->getLocalBlockSize = UA_SymEn_Basic256_getBlockSize; - symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic256_getRemoteKeyLength; - symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic256_getBlockSize; - symEncryptionAlgorithm->getLocalPlainTextBlockSize = UA_SymEn_Basic256_getPlainTextBlockSize; - symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic256_getPlainTextBlockSize; - symEncryptionAlgorithm->decrypt = UA_SymEn_Basic256_Decrypt; - symEncryptionAlgorithm->encrypt = UA_SymEn_Basic256_Encrypt; + /* Allow anonymous? */ + context->allowAnonymous = allowAnonymous; + if(allowAnonymous) { + UA_LOG_INFO(&config->logger, UA_LOGCATEGORY_SERVER, + "AccessControl: Anonymous login is enabled"); + } - /* Symmetric signature Algorithm */ + /* Allow x509 certificates? Move the plugin over. */ + if(verifyX509) { + context->verifyX509 = *verifyX509; + memset(verifyX509, 0, sizeof(UA_CertificateVerification)); + } else { + memset(&context->verifyX509, 0, sizeof(UA_CertificateVerification)); + UA_LOG_INFO(&config->logger, UA_LOGCATEGORY_SERVER, + "AccessControl: x509 certificate user authentication is enabled"); + } - UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm = - &symmetricModule->cryptoModule.signatureAlgorithm; - symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); - symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic256_getKeyLength; - symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic256_getKeyLength; - symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Basic256_getSignatureSize; - symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic256_getSignatureSize; - symSignatureAlgorithm->verify = UA_SymSig_Basic256_Verify; - symSignatureAlgorithm->sign = UA_SymSig_Basic256_Sign; + /* Copy username/password to the access control plugin */ + if(usernamePasswordLoginSize > 0) { + context->usernamePasswordLogin = (UA_UsernamePasswordLogin*) + UA_malloc(usernamePasswordLoginSize * sizeof(UA_UsernamePasswordLogin)); + if(!context->usernamePasswordLogin) + return UA_STATUSCODE_BADOUTOFMEMORY; + context->usernamePasswordLoginSize = usernamePasswordLoginSize; + for(size_t i = 0; i < usernamePasswordLoginSize; i++) { + UA_String_copy(&usernamePasswordLogin[i].username, + &context->usernamePasswordLogin[i].username); + UA_String_copy(&usernamePasswordLogin[i].password, + &context->usernamePasswordLogin[i].password); + } + } - /* set the policy context */ + /* Set the allowed policies */ + size_t policies = 0; + if(allowAnonymous) + policies++; + if(verifyX509) + policies++; + if(usernamePasswordLoginSize > 0) + policies++; + ac->userTokenPoliciesSize = 0; + ac->userTokenPolicies = (UA_UserTokenPolicy *) + UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + if(!ac->userTokenPolicies) + return UA_STATUSCODE_BADOUTOFMEMORY; + ac->userTokenPoliciesSize = policies; - retval = UA_Policy_Basic256_New_Context (policy, localPrivateKey, logger); - if (retval != UA_STATUSCODE_GOOD) { - UA_ByteString_clear (&policy->localCertificate); - return retval; + policies = 0; + if(allowAnonymous) { + ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS; + ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY); + policies++; } - policy->clear = UA_Policy_Basic256_Clear_Context; - /* Use the same signature algorithm as the asymmetric component for - certificate signing (see standard) */ - policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + if(verifyX509) { + ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_CERTIFICATE; + ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(CERTIFICATE_POLICY); +#if UA_LOGLEVEL <= 400 + if(UA_ByteString_equal(userTokenPolicyUri, &UA_SECURITY_POLICY_NONE_URI)) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_SERVER, + "x509 Certificate Authentication configured, " + "but no encrypting SecurityPolicy. " + "This can leak credentials on the network."); + } +#endif + UA_ByteString_copy(userTokenPolicyUri, + &ac->userTokenPolicies[policies].securityPolicyUri); + policies++; + } + if(usernamePasswordLoginSize > 0) { + ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME; + ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY); +#if UA_LOGLEVEL <= 400 + if(UA_ByteString_equal(userTokenPolicyUri, &UA_SECURITY_POLICY_NONE_URI)) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_SERVER, + "Username/Password Authentication configured, " + "but no encrypting SecurityPolicy. " + "This can leak credentials on the network."); + } +#endif + UA_ByteString_copy(userTokenPolicyUri, + &ac->userTokenPolicies[policies].securityPolicyUri); + } return UA_STATUSCODE_GOOD; } -#endif -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/openssl/ua_openssl_basic256sha256.c" ***********************************/ +/**** amalgamated original file "/plugins/ua_nodestore_ziptree.c" ****/ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. * - * Copyright 2020 (c) Wind River Systems, Inc. - * Copyright 2020 (c) basysKom GmbH + * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH */ -/* -modification history --------------------- -01feb20,lan written -*/ +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((uintptr_t)ptr - offsetof(type,member)) +#endif -#ifdef UA_ENABLE_ENCRYPTION_OPENSSL +struct NodeEntry; +typedef struct NodeEntry NodeEntry; +struct NodeEntry { + ZIP_ENTRY(NodeEntry) zipfields; + UA_UInt32 nodeIdHash; + UA_UInt16 refCount; /* How many consumers have a reference to the node? */ + UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */ + NodeEntry *orig; /* If a copy is made to replace a node, track that we + * replace only the node from which the copy was made. + * Important for concurrent operations. */ + UA_NodeId nodeId; /* This is actually a UA_Node that also starts with a NodeId */ +}; -#include <openssl/hmac.h> -#include <openssl/sha.h> -#include <openssl/rsa.h> -#include <openssl/x509.h> -#include <openssl/rand.h> -#include <openssl/rsa.h> +/* Absolute ordering for NodeIds */ +static enum ZIP_CMP +cmpNodeId(const void *a, const void *b) { + const NodeEntry *aa = (const NodeEntry*)a; + const NodeEntry *bb = (const NodeEntry*)b; -#define UA_SHA256_LENGTH 32 /* 256 bit */ -#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42 -#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32 -#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH 32 -#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16 -#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16 -#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256 -#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512 + /* Compare hash */ + if(aa->nodeIdHash < bb->nodeIdHash) + return ZIP_CMP_LESS; + if(aa->nodeIdHash > bb->nodeIdHash) + return ZIP_CMP_MORE; -typedef struct { - EVP_PKEY * localPrivateKey; - UA_ByteString localCertThumbprint; - const UA_Logger * logger; -} Policy_Context_Basic256Sha256; + /* Compore nodes in detail */ + return (enum ZIP_CMP)UA_NodeId_order(&aa->nodeId, &bb->nodeId); +} + +ZIP_HEAD(NodeTree, NodeEntry); +typedef struct NodeTree NodeTree; typedef struct { - UA_ByteString localSymSigningKey; - UA_ByteString localSymEncryptingKey; - UA_ByteString localSymIv; - UA_ByteString remoteSymSigningKey; - UA_ByteString remoteSymEncryptingKey; - UA_ByteString remoteSymIv; + NodeTree root; - Policy_Context_Basic256Sha256 * policyContext; - UA_ByteString remoteCertificate; - X509 * remoteCertificateX509; /* X509 */ -} Channel_Context_Basic256Sha256; + /* Maps ReferenceTypeIndex to the NodeId of the ReferenceType */ + UA_NodeId referenceTypeIds[UA_REFERENCETYPESET_MAX]; + UA_Byte referenceTypeCounter; +} ZipContext; -/* create the policy context */ +ZIP_FUNCTIONS(NodeTree, NodeEntry, zipfields, NodeEntry, zipfields, cmpNodeId) -static UA_StatusCode -UA_Policy_New_Context (UA_SecurityPolicy * securityPolicy, - const UA_ByteString localPrivateKey, - const UA_Logger * logger) { - Policy_Context_Basic256Sha256 * context = (Policy_Context_Basic256Sha256 *) - UA_malloc (sizeof (Policy_Context_Basic256Sha256)); - if (context == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; +static NodeEntry * +newEntry(UA_NodeClass nodeClass) { + size_t size = sizeof(NodeEntry) - sizeof(UA_NodeId); + switch(nodeClass) { + case UA_NODECLASS_OBJECT: + size += sizeof(UA_ObjectNode); + break; + case UA_NODECLASS_VARIABLE: + size += sizeof(UA_VariableNode); + break; + case UA_NODECLASS_METHOD: + size += sizeof(UA_MethodNode); + break; + case UA_NODECLASS_OBJECTTYPE: + size += sizeof(UA_ObjectTypeNode); + break; + case UA_NODECLASS_VARIABLETYPE: + size += sizeof(UA_VariableTypeNode); + break; + case UA_NODECLASS_REFERENCETYPE: + size += sizeof(UA_ReferenceTypeNode); + break; + case UA_NODECLASS_DATATYPE: + size += sizeof(UA_DataTypeNode); + break; + case UA_NODECLASS_VIEW: + size += sizeof(UA_ViewNode); + break; + default: + return NULL; } - - context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey); + NodeEntry *entry = (NodeEntry*)UA_calloc(1, size); + if(!entry) + return NULL; + UA_Node *node = (UA_Node*)&entry->nodeId; + node->head.nodeClass = nodeClass; + return entry; +} - if (!context->localPrivateKey) { - UA_free (context); - return UA_STATUSCODE_BADINVALIDARGUMENT; - } +static void +deleteEntry(NodeEntry *entry) { + UA_Node_clear((UA_Node*)&entry->nodeId); + UA_free(entry); +} - UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint ( - &securityPolicy->localCertificate, - &context->localCertThumbprint, true - ); - if (retval != UA_STATUSCODE_GOOD) { - EVP_PKEY_free(context->localPrivateKey); - UA_free (context); - return retval; +static void +cleanupEntry(NodeEntry *entry) { + if(entry->refCount > 0) + return; + if(entry->deleted) { + deleteEntry(entry); + return; } + UA_NodeHead *head = (UA_NodeHead*)&entry->nodeId; + for(size_t i = 0; i < head->referencesSize; i++) { + UA_NodeReferenceKind *rk = &head->references[i]; + if(rk->targetsSize > 16 && !rk->hasRefTree) + UA_NodeReferenceKind_switch(rk); + } +} - context->logger = logger; - securityPolicy->policyContext = context; +/***********************/ +/* Interface functions */ +/***********************/ - return UA_STATUSCODE_GOOD; +/* Not yet inserted into the ZipContext */ +static UA_Node * +zipNsNewNode(void *nsCtx, UA_NodeClass nodeClass) { + NodeEntry *entry = newEntry(nodeClass); + if(!entry) + return NULL; + return (UA_Node*)&entry->nodeId; } -/* clear the policy context */ - +/* Not yet inserted into the ZipContext */ static void -UA_Policy_Clear_Context (UA_SecurityPolicy *policy) { - if (policy == NULL) - return; - - UA_ByteString_deleteMembers(&policy->localCertificate); +zipNsDeleteNode(void *nsCtx, UA_Node *node) { + deleteEntry(container_of(node, NodeEntry, nodeId)); +} - /* delete all allocated members in the context */ +static const UA_Node * +zipNsGetNode(void *nsCtx, const UA_NodeId *nodeId) { + ZipContext *ns = (ZipContext*)nsCtx; + NodeEntry dummy; + dummy.nodeIdHash = UA_NodeId_hash(nodeId); + dummy.nodeId = *nodeId; + NodeEntry *entry = ZIP_FIND(NodeTree, &ns->root, &dummy); + if(!entry) + return NULL; + ++entry->refCount; + return (const UA_Node*)&entry->nodeId; +} - Policy_Context_Basic256Sha256 * pc = (Policy_Context_Basic256Sha256 *) - policy->policyContext; - EVP_PKEY_free(pc->localPrivateKey); - UA_ByteString_deleteMembers (&pc->localCertThumbprint); - UA_free (pc); - return; +static void +zipNsReleaseNode(void *nsCtx, const UA_Node *node) { + if(!node) + return; + NodeEntry *entry = container_of(node, NodeEntry, nodeId); + UA_assert(entry->refCount > 0); + --entry->refCount; + cleanupEntry(entry); } -/* create the channel context */ +static UA_StatusCode +zipNsGetNodeCopy(void *nsCtx, const UA_NodeId *nodeId, + UA_Node **outNode) { + /* Find the node */ + const UA_Node *node = zipNsGetNode(nsCtx, nodeId); + if(!node) + return UA_STATUSCODE_BADNODEIDUNKNOWN; -static UA_StatusCode -UA_ChannelModule_New_Context (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * remoteCertificate, - void ** channelContext) { - if (securityPolicy == NULL || remoteCertificate == NULL || - channelContext == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } - Channel_Context_Basic256Sha256 * context = (Channel_Context_Basic256Sha256 *) - UA_malloc (sizeof (Channel_Context_Basic256Sha256)); - if (context == NULL) { + /* Create the new entry */ + NodeEntry *ne = newEntry(node->head.nodeClass); + if(!ne) { + zipNsReleaseNode(nsCtx, node); return UA_STATUSCODE_BADOUTOFMEMORY; } - UA_ByteString_init(&context->localSymSigningKey); - UA_ByteString_init(&context->localSymEncryptingKey); - UA_ByteString_init(&context->localSymIv); - UA_ByteString_init(&context->remoteSymSigningKey); - UA_ByteString_init(&context->remoteSymEncryptingKey); - UA_ByteString_init(&context->remoteSymIv); - - UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate, - remoteCertificate); - if (retval != UA_STATUSCODE_GOOD) { - UA_free (context); + /* Copy the node content */ + UA_Node *nnode = (UA_Node*)&ne->nodeId; + UA_StatusCode retval = UA_Node_copy(node, nnode); + zipNsReleaseNode(nsCtx, node); + if(retval != UA_STATUSCODE_GOOD) { + deleteEntry(ne); return retval; } - /* decode to X509 */ - context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate); - if (context->remoteCertificateX509 == NULL) { - UA_ByteString_clear (&context->remoteCertificate); - UA_free (context); - } + ne->orig = container_of(node, NodeEntry, nodeId); + *outNode = nnode; + return UA_STATUSCODE_GOOD; +} - context->policyContext = (Policy_Context_Basic256Sha256 *) - (securityPolicy->policyContext); +static UA_StatusCode +zipNsInsertNode(void *nsCtx, UA_Node *node, UA_NodeId *addedNodeId) { + NodeEntry *entry = container_of(node, NodeEntry, nodeId); + ZipContext *ns = (ZipContext*)nsCtx; - *channelContext = context; + /* Ensure that the NodeId is unique */ + NodeEntry dummy; + memset(&dummy, 0, sizeof(NodeEntry)); + dummy.nodeId = node->head.nodeId; + if(node->head.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC && + node->head.nodeId.identifier.numeric == 0) { + do { /* Create a random nodeid until we find an unoccupied id */ + UA_UInt32 numId = UA_UInt32_random(); +#if SIZE_MAX <= UA_UINT32_MAX + /* The compressed "immediate" representation of nodes does not + * support the full range on 32bit systems. Generate smaller + * identifiers as they can be stored more compactly. */ + if(numId >= (0x01 << 24)) + numId = numId % (0x01 << 24); +#endif + node->head.nodeId.identifier.numeric = numId; + dummy.nodeId.identifier.numeric = numId; + dummy.nodeIdHash = UA_NodeId_hash(&node->head.nodeId); + } while(ZIP_FIND(NodeTree, &ns->root, &dummy)); + } else { + dummy.nodeIdHash = UA_NodeId_hash(&node->head.nodeId); + if(ZIP_FIND(NodeTree, &ns->root, &dummy)) { /* The nodeid exists */ + deleteEntry(entry); + return UA_STATUSCODE_BADNODEIDEXISTS; + } + } - UA_LOG_INFO (securityPolicy->logger, - UA_LOGCATEGORY_SECURITYPOLICY, - "The basic256sha256 security policy channel with openssl is created."); + /* Copy the NodeId */ + if(addedNodeId) { + UA_StatusCode retval = UA_NodeId_copy(&node->head.nodeId, addedNodeId); + if(retval != UA_STATUSCODE_GOOD) { + deleteEntry(entry); + return retval; + } + } - return UA_STATUSCODE_GOOD; -} + /* For new ReferencetypeNodes add to the index map */ + if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) { + UA_ReferenceTypeNode *refNode = &node->referenceTypeNode; + if(ns->referenceTypeCounter >= UA_REFERENCETYPESET_MAX) { + deleteEntry(entry); + return UA_STATUSCODE_BADINTERNALERROR; + } -/* delete the channel context */ + UA_StatusCode retval = + UA_NodeId_copy(&node->head.nodeId, &ns->referenceTypeIds[ns->referenceTypeCounter]); + if(retval != UA_STATUSCODE_GOOD) { + deleteEntry(entry); + return UA_STATUSCODE_BADINTERNALERROR; + } -static void -UA_ChannelModule_Delete_Context (void * channelContext) { - if (channelContext != NULL) { - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) - channelContext; - X509_free (cc->remoteCertificateX509); - UA_ByteString_deleteMembers (&cc->remoteCertificate); - UA_ByteString_deleteMembers (&cc->localSymSigningKey); - UA_ByteString_deleteMembers (&cc->localSymEncryptingKey); - UA_ByteString_deleteMembers (&cc->localSymIv); - UA_ByteString_deleteMembers (&cc->remoteSymSigningKey); - UA_ByteString_deleteMembers (&cc->remoteSymEncryptingKey); - UA_ByteString_deleteMembers (&cc->remoteSymIv); + /* Assign the ReferenceTypeIndex to the new ReferenceTypeNode */ + refNode->referenceTypeIndex = ns->referenceTypeCounter; + refNode->subTypes = UA_REFTYPESET(ns->referenceTypeCounter); - UA_LOG_INFO (cc->policyContext->logger, - UA_LOGCATEGORY_SECURITYPOLICY, - "The basic256sha256 security policy channel with openssl is deleted."); - UA_free (cc); + ns->referenceTypeCounter++; } + + /* Insert the node */ + entry->nodeIdHash = dummy.nodeIdHash; + ZIP_INSERT(NodeTree, &ns->root, entry, UA_UInt32_random()); + return UA_STATUSCODE_GOOD; } -/* Verifies the signature of the message using the provided keys in the context. - * AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 - */ +static UA_StatusCode +zipNsReplaceNode(void *nsCtx, UA_Node *node) { + /* Find the node */ + const UA_Node *oldNode = zipNsGetNode(nsCtx, &node->head.nodeId); + if(!oldNode) { + deleteEntry(container_of(node, NodeEntry, nodeId)); + return UA_STATUSCODE_BADNODEIDUNKNOWN; + } -static UA_StatusCode -UA_AsySig_Basic256Sha256_Verify (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - const UA_ByteString * signature) { - if (securityPolicy == NULL || message == NULL || signature == NULL || - channelContext == NULL) { + /* Test if the copy is current */ + NodeEntry *entry = container_of(node, NodeEntry, nodeId); + NodeEntry *oldEntry = container_of(oldNode, NodeEntry, nodeId); + if(oldEntry != entry->orig) { + /* The node was already updated since the copy was made */ + deleteEntry(entry); + zipNsReleaseNode(nsCtx, oldNode); return UA_STATUSCODE_BADINTERNALERROR; - } + } - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) - channelContext; - UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify (message, - cc->remoteCertificateX509, signature); + /* Replace */ + ZipContext *ns = (ZipContext*)nsCtx; + ZIP_REMOVE(NodeTree, &ns->root, oldEntry); + entry->nodeIdHash = oldEntry->nodeIdHash; + ZIP_INSERT(NodeTree, &ns->root, entry, ZIP_RANK(entry, zipfields)); + oldEntry->deleted = true; - return retval; + zipNsReleaseNode(nsCtx, oldNode); + return UA_STATUSCODE_GOOD; } -/* Compares the supplied certificate with the certificate - * in the endpoit context - */ - static UA_StatusCode -UA_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * certificateThumbprint) { - if (securityPolicy == NULL || certificateThumbprint == NULL) { - return UA_STATUSCODE_BADINVALIDARGUMENT; - } - Policy_Context_Basic256Sha256 *pc = (Policy_Context_Basic256Sha256 *) - securityPolicy->policyContext; - if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) - return UA_STATUSCODE_BADCERTIFICATEINVALID; +zipNsRemoveNode(void *nsCtx, const UA_NodeId *nodeId) { + ZipContext *ns = (ZipContext*)nsCtx; + NodeEntry dummy; + dummy.nodeIdHash = UA_NodeId_hash(nodeId); + dummy.nodeId = *nodeId; + NodeEntry *entry = ZIP_FIND(NodeTree, &ns->root, &dummy); + if(!entry) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + ZIP_REMOVE(NodeTree, &ns->root, entry); + entry->deleted = true; + cleanupEntry(entry); return UA_STATUSCODE_GOOD; } -/* Generates a thumbprint for the specified certificate */ - -static UA_StatusCode -UA_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * certificate, - UA_ByteString * thumbprint) { - return UA_Openssl_X509_GetCertificateThumbprint (certificate, - thumbprint, false); +static const UA_NodeId * +zipNsGetReferenceTypeId(void *nsCtx, UA_Byte refTypeIndex) { + ZipContext *ns = (ZipContext*)nsCtx; + if(refTypeIndex >= ns->referenceTypeCounter) + return NULL; + return &ns->referenceTypeIds[refTypeIndex]; } -static UA_StatusCode -UA_Asym_Basic256Sha256_Decrypt (const UA_SecurityPolicy *securityPolicy, - void * channelContext, - UA_ByteString * data) { - if (securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINVALIDARGUMENT; +struct VisitorData { + UA_NodestoreVisitor visitor; + void *visitorContext; +}; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) - channelContext; - UA_StatusCode ret = UA_Openssl_RSA_Oaep_Decrypt (data, - cc->policyContext->localPrivateKey); - return ret; +static void +nodeVisitor(NodeEntry *entry, void *data) { + struct VisitorData *d = (struct VisitorData*)data; + d->visitor(d->visitorContext, (UA_Node*)&entry->nodeId); } -static size_t -UA_Asym_Basic256Sha256_getRemoteSignatureSize ( - const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; +static void +zipNsIterate(void *nsCtx, UA_NodestoreVisitor visitor, + void *visitorCtx) { + struct VisitorData d; + d.visitor = visitor; + d.visitorContext = visitorCtx; + ZipContext *ns = (ZipContext*)nsCtx; + ZIP_ITER(NodeTree, &ns->root, nodeVisitor, &d); +} - const Channel_Context_Basic256Sha256 * cc = (const Channel_Context_Basic256Sha256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - UA_assert (keyLen == 256); /* 256 bytes 2048 bit */ - return (size_t) keyLen; +static void +deleteNodeVisitor(NodeEntry *entry, void *data) { + deleteEntry(entry); } -static size_t -UA_AsySig_Basic256Sha256_getLocalSignatureSize (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; +/***********************/ +/* Nodestore Lifecycle */ +/***********************/ - Policy_Context_Basic256Sha256 * pc = - (Policy_Context_Basic256Sha256 *) securityPolicy->policyContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); - UA_assert (keyLen == 256); /* 256 bytes 2048 bits */ +static void +zipNsClear(void *nsCtx) { + if (!nsCtx) + return; + ZipContext *ns = (ZipContext*)nsCtx; + ZIP_ITER(NodeTree, &ns->root, deleteNodeVisitor, NULL); - return (size_t) keyLen; + /* Clean up the ReferenceTypes index array */ + for(size_t i = 0; i < ns->referenceTypeCounter; i++) + UA_NodeId_clear(&ns->referenceTypeIds[i]); + + UA_free(ns); } -static size_t -UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; +UA_StatusCode +UA_Nodestore_ZipTree(UA_Nodestore *ns) { + /* Allocate and initialize the context */ + ZipContext *ctx = (ZipContext*)UA_malloc(sizeof(ZipContext)); + if(!ctx) + return UA_STATUSCODE_BADOUTOFMEMORY; - const Channel_Context_Basic256Sha256 * cc = (const Channel_Context_Basic256Sha256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN; + ZIP_INIT(&ctx->root); + ctx->referenceTypeCounter = 0; + + /* Populate the nodestore */ + ns->context = (void*)ctx; + ns->clear = zipNsClear; + ns->newNode = zipNsNewNode; + ns->deleteNode = zipNsDeleteNode; + ns->getNode = zipNsGetNode; + ns->releaseNode = zipNsReleaseNode; + ns->getNodeCopy = zipNsGetNodeCopy; + ns->insertNode = zipNsInsertNode; + ns->replaceNode = zipNsReplaceNode; + ns->removeNode = zipNsRemoveNode; + ns->getReferenceTypeId = zipNsGetReferenceTypeId; + ns->iterate = zipNsIterate; + + return UA_STATUSCODE_GOOD; } -static size_t -UA_AsymEn_Basic256Sha256_getRemoteBlockSize (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; +/**** amalgamated original file "/plugins/ua_nodestore_hashmap.c" ****/ - const Channel_Context_Basic256Sha256 * cc = (const Channel_Context_Basic256Sha256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen; -} +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2014-2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ -static size_t -UA_AsymEn_Basic256Sha256_getRemoteKeyLength (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - const Channel_Context_Basic256Sha256 * cc = (const Channel_Context_Basic256Sha256 *) channelContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen); - return (size_t) keyLen * 8; -} +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((uintptr_t)ptr - offsetof(type,member)) +#endif -static UA_StatusCode -UA_Sym_Basic256Sha256_generateNonce (const UA_SecurityPolicy * sp, - UA_ByteString * out) { - UA_Int32 rc = RAND_bytes(out->data, (int) out->length); - if (rc != 1) { - return UA_STATUSCODE_BADUNEXPECTEDERROR; +/* The default Nodestore is simply a hash-map from NodeIds to Nodes. To find an + * entry, iterate over candidate positions according to the NodeId hash. + * + * - Tombstone or non-matching NodeId: continue searching + * - Matching NodeId: Return the entry + * - NULL: Abort the search */ + +typedef struct UA_NodeMapEntry { + struct UA_NodeMapEntry *orig; /* the version this is a copy from (or NULL) */ + UA_UInt16 refCount; /* How many consumers have a reference to the node? */ + UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */ + UA_Node node; +} UA_NodeMapEntry; + +#define UA_NODEMAP_MINSIZE 64 +#define UA_NODEMAP_TOMBSTONE ((UA_NodeMapEntry*)0x01) + +typedef struct { + UA_NodeMapEntry *entry; + UA_UInt32 nodeIdHash; +} UA_NodeMapSlot; + +typedef struct { + UA_NodeMapSlot *slots; + UA_UInt32 size; + UA_UInt32 count; + UA_UInt32 sizePrimeIndex; + + /* Maps ReferenceTypeIndex to the NodeId of the ReferenceType */ + UA_NodeId referenceTypeIds[UA_REFERENCETYPESET_MAX]; + UA_Byte referenceTypeCounter; +} UA_NodeMap; + +/*********************/ +/* HashMap Utilities */ +/*********************/ + +/* The size of the hash-map is always a prime number. They are chosen to be + * close to the next power of 2. So the size ca. doubles with each prime. */ +static UA_UInt32 const primes[] = { + 7, 13, 31, 61, 127, 251, + 509, 1021, 2039, 4093, 8191, 16381, + 32749, 65521, 131071, 262139, 524287, 1048573, + 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, + 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291 +}; + +static UA_UInt32 mod(UA_UInt32 h, UA_UInt32 size) { return h % size; } +static UA_UInt32 mod2(UA_UInt32 h, UA_UInt32 size) { return 1 + (h % (size - 2)); } + +static UA_UInt16 +higher_prime_index(UA_UInt32 n) { + UA_UInt16 low = 0; + UA_UInt16 high = (UA_UInt16)(sizeof(primes) / sizeof(UA_UInt32)); + while(low != high) { + UA_UInt16 mid = (UA_UInt16)(low + ((high - low) / 2)); + if(n > primes[mid]) + low = (UA_UInt16)(mid + 1); + else + high = mid; } - return UA_STATUSCODE_GOOD; + return low; } -static size_t -UA_SymEn_Basic256Sha256_getLocalKeyLength (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - /* 32 bytes 256 bits */ - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH; -} +/* Returns an empty slot or null if the nodeid exists or if no empty slot is found. */ +static UA_NodeMapSlot * +findFreeSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) { + UA_UInt32 h = UA_NodeId_hash(nodeid); + UA_UInt32 size = ns->size; + UA_UInt64 idx = mod(h, size); /* Use 64bit container to avoid overflow */ + UA_UInt32 startIdx = (UA_UInt32)idx; + UA_UInt32 hash2 = mod2(h, size); -static size_t -UA_SymEn_Basic256Sha256_getLocalBlockSize ( - const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE; -} + UA_NodeMapSlot *candidate = NULL; + do { + UA_NodeMapSlot *slot = &ns->slots[(UA_UInt32)idx]; -static size_t -UA_SymSig_Basic256Sha256_getLocalKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - /* 32 bytes 256 bits */ - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH; + if(slot->entry > UA_NODEMAP_TOMBSTONE) { + /* A Node with the NodeId does already exist */ + if(slot->nodeIdHash == h && + UA_NodeId_equal(&slot->entry->node.head.nodeId, nodeid)) + return NULL; + } else { + /* Found a candidate node */ + if(!candidate) + candidate = slot; + /* No matching node can come afterwards */ + if(slot->entry == NULL) + return candidate; + } + + idx += hash2; + if(idx >= size) + idx -= size; + } while((UA_UInt32)idx != startIdx); + + return candidate; } +/* The occupancy of the table after the call will be about 50% */ static UA_StatusCode -UA_Sym_Basic256Sha256_generateKey (const UA_SecurityPolicy * securityPolicy, - const UA_ByteString * secret, - const UA_ByteString * seed, - UA_ByteString * out) { - return UA_Openssl_Random_Key_PSHA256_Derive (secret, seed, out); +expand(UA_NodeMap *ns) { + UA_UInt32 osize = ns->size; + UA_UInt32 count = ns->count; + /* Resize only when table after removal of unused elements is either too + full or too empty */ + if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODEMAP_MINSIZE)) + return UA_STATUSCODE_GOOD; + + UA_NodeMapSlot *oslots = ns->slots; + UA_UInt32 nindex = higher_prime_index(count * 2); + UA_UInt32 nsize = primes[nindex]; + UA_NodeMapSlot *nslots= (UA_NodeMapSlot*)UA_calloc(nsize, sizeof(UA_NodeMapSlot)); + if(!nslots) + return UA_STATUSCODE_BADOUTOFMEMORY; + + ns->slots = nslots; + ns->size = nsize; + ns->sizePrimeIndex = nindex; + + /* recompute the position of every entry and insert the pointer */ + for(size_t i = 0, j = 0; i < osize && j < count; ++i) { + if(oslots[i].entry <= UA_NODEMAP_TOMBSTONE) + continue; + UA_NodeMapSlot *s = findFreeSlot(ns, &oslots[i].entry->node.head.nodeId); + UA_assert(s); + *s = oslots[i]; + ++j; + } + + UA_free(oslots); + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_ChannelModule_Basic256Sha256_setLocalSymSigningKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymSigningKey); - return UA_ByteString_copy(key, &cc->localSymSigningKey); +static UA_NodeMapEntry * +createEntry(UA_NodeClass nodeClass) { + size_t size = sizeof(UA_NodeMapEntry) - sizeof(UA_Node); + switch(nodeClass) { + case UA_NODECLASS_OBJECT: + size += sizeof(UA_ObjectNode); + break; + case UA_NODECLASS_VARIABLE: + size += sizeof(UA_VariableNode); + break; + case UA_NODECLASS_METHOD: + size += sizeof(UA_MethodNode); + break; + case UA_NODECLASS_OBJECTTYPE: + size += sizeof(UA_ObjectTypeNode); + break; + case UA_NODECLASS_VARIABLETYPE: + size += sizeof(UA_VariableTypeNode); + break; + case UA_NODECLASS_REFERENCETYPE: + size += sizeof(UA_ReferenceTypeNode); + break; + case UA_NODECLASS_DATATYPE: + size += sizeof(UA_DataTypeNode); + break; + case UA_NODECLASS_VIEW: + size += sizeof(UA_ViewNode); + break; + default: + return NULL; + } + UA_NodeMapEntry *entry = (UA_NodeMapEntry*)UA_calloc(1, size); + if(!entry) + return NULL; + entry->node.head.nodeClass = nodeClass; + return entry; } -static UA_StatusCode -UA_ChannelM_Basic256Sha256_setLocalSymEncryptingKey (void * channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); - return UA_ByteString_copy(key, &cc->localSymEncryptingKey); +static void +deleteNodeMapEntry(UA_NodeMapEntry *entry) { + UA_Node_clear(&entry->node); + UA_free(entry); } -static UA_StatusCode -UA_ChannelM_Basic256Sha256_setLocalSymIv (void * channelContext, - const UA_ByteString * iv) { - if (iv == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - UA_ByteString_deleteMembers(&cc->localSymIv); - return UA_ByteString_copy(iv, &cc->localSymIv); +static void +cleanupNodeMapEntry(UA_NodeMapEntry *entry) { + if(entry->refCount > 0) + return; + if(entry->deleted) { + deleteNodeMapEntry(entry); + return; + } + for(size_t i = 0; i < entry->node.head.referencesSize; i++) { + UA_NodeReferenceKind *rk = &entry->node.head.references[i]; + if(rk->targetsSize > 16 && !rk->hasRefTree) + UA_NodeReferenceKind_switch(rk); + } } -static size_t -UA_SymEn_Basic256Sha256_getRemoteKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - /* 32 bytes 256 bits */ - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH; +static UA_NodeMapSlot * +findOccupiedSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) { + UA_UInt32 h = UA_NodeId_hash(nodeid); + UA_UInt32 size = ns->size; + UA_UInt64 idx = mod(h, size); /* Use 64bit container to avoid overflow */ + UA_UInt32 hash2 = mod2(h, size); + UA_UInt32 startIdx = (UA_UInt32)idx; + + do { + UA_NodeMapSlot *slot= &ns->slots[(UA_UInt32)idx]; + if(slot->entry > UA_NODEMAP_TOMBSTONE) { + if(slot->nodeIdHash == h && + UA_NodeId_equal(&slot->entry->node.head.nodeId, nodeid)) + return slot; + } else { + if(slot->entry == NULL) + return NULL; /* No further entry possible */ + } + + idx += hash2; + if(idx >= size) + idx -= size; + } while((UA_UInt32)idx != startIdx); + + return NULL; } -static size_t -UA_SymEn_Basic256Sha256_getRemoteBlockSize (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE; +/***********************/ +/* Interface functions */ +/***********************/ + +static UA_Node * +UA_NodeMap_newNode(void *context, UA_NodeClass nodeClass) { + UA_NodeMapEntry *entry = createEntry(nodeClass); + if(!entry) + return NULL; + return &entry->node; } -static size_t -UA_SymSig_Basic256Sha256_getRemoteKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - /* 32 bytes 256 bits */ - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH; +static void +UA_NodeMap_deleteNode(void *context, UA_Node *node) { + UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node); + UA_assert(&entry->node == node); + deleteNodeMapEntry(entry); } -static UA_StatusCode -UA_ChannelM_Basic256Sha256_setRemoteSymSigningKey (void *channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); - return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +static const UA_Node * +UA_NodeMap_getNode(void *context, const UA_NodeId *nodeid) { + UA_NodeMap *ns = (UA_NodeMap*)context; + UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid); + if(!slot) + return NULL; + ++slot->entry->refCount; + return &slot->entry->node; } -static UA_StatusCode -UA_ChannelM_Basic256Sha256_setRemoteSymEncryptingKey (void *channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); - return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +static void +UA_NodeMap_releaseNode(void *context, const UA_Node *node) { + if (!node) + return; + UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node); + UA_assert(&entry->node == node); + UA_assert(entry->refCount > 0); + --entry->refCount; + cleanupNodeMapEntry(entry); } static UA_StatusCode -UA_ChannelM_Basic256Sha256_setRemoteSymIv (void *channelContext, - const UA_ByteString * key) { - if (key == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - UA_ByteString_deleteMembers(&cc->remoteSymIv); - return UA_ByteString_copy(key, &cc->remoteSymIv); +UA_NodeMap_getNodeCopy(void *context, const UA_NodeId *nodeid, + UA_Node **outNode) { + UA_NodeMap *ns = (UA_NodeMap*)context; + UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid); + if(!slot) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + UA_NodeMapEntry *entry = slot->entry; + UA_NodeMapEntry *newItem = createEntry(entry->node.head.nodeClass); + if(!newItem) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_StatusCode retval = UA_Node_copy(&entry->node, &newItem->node); + if(retval == UA_STATUSCODE_GOOD) { + newItem->orig = entry; /* Store the pointer to the original */ + *outNode = &newItem->node; + } else { + deleteNodeMapEntry(newItem); + } + return retval; } static UA_StatusCode -UA_AsySig_Basic256Sha256_sign (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Policy_Context_Basic256Sha256 * pc = - (Policy_Context_Basic256Sha256 *) securityPolicy->policyContext; - return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign (message, pc->localPrivateKey, - signature); +UA_NodeMap_removeNode(void *context, const UA_NodeId *nodeid) { + UA_NodeMap *ns = (UA_NodeMap*)context; + UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid); + if(!slot) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + + UA_NodeMapEntry *entry = slot->entry; + slot->entry = UA_NODEMAP_TOMBSTONE; + UA_atomic_sync(); /* Set the tombstone before cleaning up. E.g. if the + * nodestore is accessed from an interrupt. */ + entry->deleted = true; + cleanupNodeMapEntry(entry); + --ns->count; + /* Downsize the hashmap if it is very empty */ + if(ns->count * 8 < ns->size && ns->size > UA_NODEMAP_MINSIZE) + expand(ns); /* Can fail. Just continue with the bigger hashmap. */ + return UA_STATUSCODE_GOOD; } +/* + * If this function fails in any way, the node parameter is deleted here, + * so the caller function does not need to take care of it anymore + */ static UA_StatusCode -UA_AsymEn_Basic256Sha256_encrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if (securityPolicy == NULL || channelContext == NULL || - data == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - return UA_Openssl_RSA_OAEP_Encrypt (data, UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN, - cc->remoteCertificateX509); -} +UA_NodeMap_insertNode(void *context, UA_Node *node, + UA_NodeId *addedNodeId) { + UA_NodeMap *ns = (UA_NodeMap*)context; + if(ns->size * 3 <= ns->count * 4) { + if(expand(ns) != UA_STATUSCODE_GOOD){ + deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); + return UA_STATUSCODE_BADINTERNALERROR; + } + } -static size_t -UA_SymSig_Basic256Sha256_getRemoteSignatureSize (const UA_SecurityPolicy *securityPolicy, - const void *channelContext) { - return UA_SHA256_LENGTH; + UA_NodeMapSlot *slot; + if(node->head.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC && + node->head.nodeId.identifier.numeric == 0) { + /* Create a random nodeid: Start at least with 50,000 to make sure we + * don not conflict with nodes from the spec. If we find a conflict, we + * just try another identifier until we have tried all possible + * identifiers. Since the size is prime and we don't change the increase + * val, we will reach the starting id again. E.g. adding a nodeset will + * create children while there are still other nodes which need to be + * created. Thus the node ids may collide. */ + UA_UInt32 size = ns->size; + UA_UInt64 identifier = mod(50000 + size+1, UA_UINT32_MAX); /* Use 64bit to + * avoid overflow */ + UA_UInt32 increase = mod2(ns->count+1, size); + UA_UInt32 startId = (UA_UInt32)identifier; /* mod ensures us that the id + * is a valid 32 bit integer */ + + do { + node->head.nodeId.identifier.numeric = (UA_UInt32)identifier; + slot = findFreeSlot(ns, &node->head.nodeId); + if(slot) + break; + identifier += increase; + if(identifier >= size) + identifier -= size; +#if SIZE_MAX <= UA_UINT32_MAX + /* The compressed "immediate" representation of nodes does not + * support the full range on 32bit systems. Generate smaller + * identifiers as they can be stored more compactly. */ + if(identifier >= (0x01 << 24)) + identifier = identifier % (0x01 << 24); +#endif + } while((UA_UInt32)identifier != startId); + } else { + slot = findFreeSlot(ns, &node->head.nodeId); + } + + if(!slot) { + deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); + return UA_STATUSCODE_BADNODEIDEXISTS; + } + + /* Copy the NodeId */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(addedNodeId) { + retval = UA_NodeId_copy(&node->head.nodeId, addedNodeId); + if(retval != UA_STATUSCODE_GOOD) { + deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); + return retval; + } + } + + /* For new ReferencetypeNodes add to the index map */ + if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) { + UA_ReferenceTypeNode *refNode = &node->referenceTypeNode; + if(ns->referenceTypeCounter >= UA_REFERENCETYPESET_MAX) { + deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); + return UA_STATUSCODE_BADINTERNALERROR; + } + + retval = UA_NodeId_copy(&node->head.nodeId, &ns->referenceTypeIds[ns->referenceTypeCounter]); + if(retval != UA_STATUSCODE_GOOD) { + deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node)); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Assign the ReferenceTypeIndex to the new ReferenceTypeNode */ + refNode->referenceTypeIndex = ns->referenceTypeCounter; + refNode->subTypes = UA_REFTYPESET(ns->referenceTypeCounter); + + ns->referenceTypeCounter++; + } + + /* Insert the node */ + UA_NodeMapEntry *newEntry = container_of(node, UA_NodeMapEntry, node); + slot->nodeIdHash = UA_NodeId_hash(&node->head.nodeId); + UA_atomic_sync(); /* Set the hash first */ + slot->entry = newEntry; + ++ns->count; + return retval; } static UA_StatusCode -UA_SymSig_Basic256Sha256_verify (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - const UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - return UA_OpenSSL_HMAC_SHA256_Verify (message, - &cc->remoteSymSigningKey, - signature); -} +UA_NodeMap_replaceNode(void *context, UA_Node *node) { + UA_NodeMap *ns = (UA_NodeMap*)context; + UA_NodeMapEntry *newEntry = container_of(node, UA_NodeMapEntry, node); -static UA_StatusCode -UA_SymSig_Basic256Sha256_sign (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - const UA_ByteString * message, - UA_ByteString * signature) { - if (securityPolicy == NULL || channelContext == NULL || - message == NULL || signature == NULL) + /* Find the node */ + UA_NodeMapSlot *slot = findOccupiedSlot(ns, &node->head.nodeId); + if(!slot) { + deleteNodeMapEntry(newEntry); + return UA_STATUSCODE_BADNODEIDUNKNOWN; + } + + /* The node was already updated since the copy was made? */ + UA_NodeMapEntry *oldEntry = slot->entry; + if(oldEntry != newEntry->orig) { + deleteNodeMapEntry(newEntry); return UA_STATUSCODE_BADINTERNALERROR; - - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - return UA_OpenSSL_HMAC_SHA256_Sign (message, &cc->localSymSigningKey, signature); + } + + /* Replace the entry */ + slot->entry = newEntry; + UA_atomic_sync(); + oldEntry->deleted = true; + cleanupNodeMapEntry(oldEntry); + return UA_STATUSCODE_GOOD; } -static size_t -UA_SymSig_Basic256Sha256_getLocalSignatureSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SHA256_LENGTH; +static const UA_NodeId * +UA_NodeMap_getReferenceTypeId(void *nsCtx, UA_Byte refTypeIndex) { + UA_NodeMap *ns = (UA_NodeMap*)nsCtx; + if(refTypeIndex >= ns->referenceTypeCounter) + return NULL; + return &ns->referenceTypeIds[refTypeIndex]; } -static UA_StatusCode -UA_SymEn_Basic256Sha256_decrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if(securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - return UA_OpenSSL_AES_256_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data); +static void +UA_NodeMap_iterate(void *context, UA_NodestoreVisitor visitor, + void *visitorContext) { + UA_NodeMap *ns = (UA_NodeMap*)context; + for(UA_UInt32 i = 0; i < ns->size; ++i) { + UA_NodeMapSlot *slot = &ns->slots[i]; + if(slot->entry > UA_NODEMAP_TOMBSTONE) { + /* The visitor can delete the node. So refcount here. */ + slot->entry->refCount++; + visitor(visitorContext, &slot->entry->node); + slot->entry->refCount--; + cleanupNodeMapEntry(slot->entry); + } + } } -static UA_StatusCode -UA_SymEn_Basic256Sha256_encrypt (const UA_SecurityPolicy * securityPolicy, - void * channelContext, - UA_ByteString * data) { - if(securityPolicy == NULL || channelContext == NULL || data == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - - Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext; - return UA_OpenSSL_AES_256_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data); +static void +UA_NodeMap_delete(void *context) { + /* Already cleaned up? */ + if(!context) + return; + + UA_NodeMap *ns = (UA_NodeMap*)context; + UA_UInt32 size = ns->size; + UA_NodeMapSlot *slots = ns->slots; + for(UA_UInt32 i = 0; i < size; ++i) { + if(slots[i].entry > UA_NODEMAP_TOMBSTONE) { + /* On debugging builds, check that all nodes were release */ + UA_assert(slots[i].entry->refCount == 0); + /* Delete the node */ + deleteNodeMapEntry(slots[i].entry); + } + } + UA_free(ns->slots); + + /* Clean up the ReferenceTypes index array */ + for(size_t i = 0; i < ns->referenceTypeCounter; i++) + UA_NodeId_clear(&ns->referenceTypeIds[i]); + + UA_free(ns); } -static UA_StatusCode -UA_ChannelM_Basic256Sha256_compareCertificate (const void *channelContext, - const UA_ByteString *certificate) { - if(channelContext == NULL || certificate == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - - const Channel_Context_Basic256Sha256 * cc = - (const Channel_Context_Basic256Sha256 *) channelContext; - return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509); +UA_StatusCode +UA_Nodestore_HashMap(UA_Nodestore *ns) { + /* Allocate and initialize the nodemap */ + UA_NodeMap *nodemap = (UA_NodeMap*)UA_malloc(sizeof(UA_NodeMap)); + if(!nodemap) + return UA_STATUSCODE_BADOUTOFMEMORY; + nodemap->sizePrimeIndex = higher_prime_index(UA_NODEMAP_MINSIZE); + nodemap->size = primes[nodemap->sizePrimeIndex]; + nodemap->count = 0; + nodemap->slots = (UA_NodeMapSlot*) + UA_calloc(nodemap->size, sizeof(UA_NodeMapSlot)); + if(!nodemap->slots) { + UA_free(nodemap); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + nodemap->referenceTypeCounter = 0; + + /* Populate the nodestore */ + ns->context = nodemap; + ns->clear = UA_NodeMap_delete; + ns->newNode = UA_NodeMap_newNode; + ns->deleteNode = UA_NodeMap_deleteNode; + ns->getNode = UA_NodeMap_getNode; + ns->releaseNode = UA_NodeMap_releaseNode; + ns->getNodeCopy = UA_NodeMap_getNodeCopy; + ns->insertNode = UA_NodeMap_insertNode; + ns->replaceNode = UA_NodeMap_replaceNode; + ns->removeNode = UA_NodeMap_removeNode; + ns->getReferenceTypeId = UA_NodeMap_getReferenceTypeId; + ns->iterate = UA_NodeMap_iterate; + return UA_STATUSCODE_GOOD; } -static size_t -UA_SymEn_Basic256Sha256_getLocalPlainTextBlockSize (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - return UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE; +/**** amalgamated original file "/plugins/ua_config_default.c" ****/ + +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG + * Copyright 2018 (c) Fabian Arndt, Root-Core + * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green) + * Copyright 2020 (c) Wind River Systems, Inc. + */ + +#ifdef UA_ENABLE_WEBSOCKET_SERVER +#endif + +/* Struct initialization works across ANSI C/C99/C++ if it is done when the + * variable is first declared. Assigning values to existing structs is + * heterogeneous across the three. */ +static UA_INLINE UA_UInt32Range +UA_UINT32RANGE(UA_UInt32 min, UA_UInt32 max) { + UA_UInt32Range range = {min, max}; + return range; } -static size_t -UA_AsymEn_Basic256Sha256_getLocalKeyLength (const UA_SecurityPolicy * securityPolicy, - const void * channelContext) { - if (securityPolicy == NULL || channelContext == NULL) - return UA_STATUSCODE_BADINTERNALERROR; +static UA_INLINE UA_DurationRange +UA_DURATIONRANGE(UA_Duration min, UA_Duration max) { + UA_DurationRange range = {min, max}; + return range; +} - Policy_Context_Basic256Sha256 * pc = - (Policy_Context_Basic256Sha256 *) securityPolicy->policyContext; - UA_Int32 keyLen = 0; - UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); - UA_assert (keyLen == 256); /* 256 bytes 2048 bits */ +UA_Server * +UA_Server_new(void) { + UA_ServerConfig config; + memset(&config, 0, sizeof(UA_ServerConfig)); + /* Set a default logger and NodeStore for the initialization */ + config.logger = UA_Log_Stdout_; + if(UA_STATUSCODE_GOOD != UA_Nodestore_HashMap(&config.nodestore)) { + return NULL; + } - return (size_t) keyLen * 8; + return UA_Server_newWithConfig(&config); } -/* the main entry of Basic256Sha256 */ +/*******************************/ +/* Default Connection Settings */ +/*******************************/ -UA_StatusCode -UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy * policy, - const UA_ByteString localCertificate, - const UA_ByteString localPrivateKey, - const UA_Logger * logger) { +const UA_ConnectionConfig UA_ConnectionConfig_default = { + 0, /* .protocolVersion */ + 2 << 16, /* .sendBufferSize, 64k per chunk */ + 2 << 16, /* .recvBufferSize, 64k per chunk */ + 2 << 29, /* .localMaxMessageSize, 512 MB */ + 2 << 29, /* .remoteMaxMessageSize, 512 MB */ + 2 << 14, /* .localMaxChunkCount, 16k */ + 2 << 14 /* .remoteMaxChunkCount, 16k */ +}; - UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule; - UA_SecurityPolicySymmetricModule * const symmetricModule = &policy->symmetricModule; - UA_SecurityPolicyChannelModule * const channelModule = &policy->channelModule; - UA_StatusCode retval; +/***************************/ +/* Default Server Settings */ +/***************************/ - UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY, - "The basic256sha256 security policy with openssl is added."); +#define MANUFACTURER_NAME "open62541" +#define PRODUCT_NAME "open62541 OPC UA Server" +#define PRODUCT_URI "http://open62541.org" +#define APPLICATION_NAME "open62541-based OPC UA Application" +#define APPLICATION_URI "urn:unconfigured:application" +#define APPLICATION_URI_SERVER "urn:open62541.server.application" - UA_Openssl_Init (); - memset(policy, 0, sizeof(UA_SecurityPolicy)); - policy->logger = logger; - policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256\0"); +#define STRINGIFY(arg) #arg +#define VERSION(MAJOR, MINOR, PATCH, LABEL) \ + STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL - /* set ChannelModule context */ +static UA_StatusCode +createEndpoint(UA_ServerConfig *conf, UA_EndpointDescription *endpoint, + const UA_SecurityPolicy *securityPolicy, + UA_MessageSecurityMode securityMode) { + UA_EndpointDescription_init(endpoint); - channelModule->newContext = UA_ChannelModule_New_Context; - channelModule->deleteContext = UA_ChannelModule_Delete_Context; - channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic256Sha256_setLocalSymSigningKey; - channelModule->setLocalSymEncryptingKey = UA_ChannelM_Basic256Sha256_setLocalSymEncryptingKey; - channelModule->setLocalSymIv = UA_ChannelM_Basic256Sha256_setLocalSymIv; - channelModule->setRemoteSymSigningKey = UA_ChannelM_Basic256Sha256_setRemoteSymSigningKey; - channelModule->setRemoteSymEncryptingKey = UA_ChannelM_Basic256Sha256_setRemoteSymEncryptingKey; - channelModule->setRemoteSymIv = UA_ChannelM_Basic256Sha256_setRemoteSymIv; - channelModule->compareCertificate = UA_ChannelM_Basic256Sha256_compareCertificate; + endpoint->securityMode = securityMode; + UA_String_copy(&securityPolicy->policyUri, &endpoint->securityPolicyUri); + endpoint->transportProfileUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"); - retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); + /* Add security level value for the corresponding message security mode */ + endpoint->securityLevel = (UA_Byte) securityMode; - if (retval != UA_STATUSCODE_GOOD) + /* Enable all login mechanisms from the access control plugin */ + UA_StatusCode retval = UA_Array_copy(conf->accessControl.userTokenPolicies, + conf->accessControl.userTokenPoliciesSize, + (void **)&endpoint->userIdentityTokens, + &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + if(retval != UA_STATUSCODE_GOOD){ + UA_String_clear(&endpoint->securityPolicyUri); + UA_String_clear(&endpoint->transportProfileUri); return retval; + } + endpoint->userIdentityTokensSize = conf->accessControl.userTokenPoliciesSize; - /* AsymmetricModule - signature algorithm */ + UA_String_copy(&securityPolicy->localCertificate, &endpoint->serverCertificate); + UA_ApplicationDescription_copy(&conf->applicationDescription, &endpoint->server); - UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm = - &asymmetricModule->cryptoModule.signatureAlgorithm; - asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0"); - asySigAlgorithm->verify = UA_AsySig_Basic256Sha256_Verify; - asySigAlgorithm->getRemoteSignatureSize = UA_Asym_Basic256Sha256_getRemoteSignatureSize; - asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic256Sha256_getLocalSignatureSize; - asySigAlgorithm->sign = UA_AsySig_Basic256Sha256_sign; - asySigAlgorithm->getLocalKeyLength = NULL; - asySigAlgorithm->getRemoteKeyLength = NULL; + return UA_STATUSCODE_GOOD; +} - /* AsymmetricModule encryption algorithm */ +static const size_t usernamePasswordsSize = 2; +static UA_UsernamePasswordLogin usernamePasswords[2] = { + {UA_STRING_STATIC("user1"), UA_STRING_STATIC("password")}, + {UA_STRING_STATIC("user2"), UA_STRING_STATIC("password1")}}; - UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg = - &asymmetricModule->cryptoModule.encryptionAlgorithm; - asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); - asymEncryAlg->decrypt = UA_Asym_Basic256Sha256_Decrypt; - asymEncryAlg->getRemotePlainTextBlockSize = - UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize; - asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic256Sha256_getRemoteBlockSize; - asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic256Sha256_getRemoteKeyLength; - asymEncryAlg->encrypt = UA_AsymEn_Basic256Sha256_encrypt; - asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic256Sha256_getLocalKeyLength; - asymEncryAlg->getLocalPlainTextBlockSize = NULL; - asymEncryAlg->getLocalBlockSize = NULL; +static UA_StatusCode +setDefaultConfig(UA_ServerConfig *conf) { + if(!conf) + return UA_STATUSCODE_BADINVALIDARGUMENT; - /* asymmetricModule */ + if(conf->nodestore.context == NULL) + UA_Nodestore_HashMap(&conf->nodestore); - asymmetricModule->compareCertificateThumbprint = UA_compareCertificateThumbprint; - asymmetricModule->makeCertificateThumbprint = UA_makeCertificateThumbprint; + /* --> Start setting the default static config <-- */ + /* Allow user to set his own logger */ + if(!conf->logger.log) + conf->logger = UA_Log_Stdout_; - /* SymmetricModule */ + conf->shutdownDelay = 0.0; - symmetricModule->secureChannelNonceLength = 32; - symmetricModule->generateNonce = UA_Sym_Basic256Sha256_generateNonce; - symmetricModule->generateKey = UA_Sym_Basic256Sha256_generateKey; + /* Server Description */ + UA_BuildInfo_clear(&conf->buildInfo); + conf->buildInfo.productUri = UA_STRING_ALLOC(PRODUCT_URI); + conf->buildInfo.manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME); + conf->buildInfo.productName = UA_STRING_ALLOC(PRODUCT_NAME); + conf->buildInfo.softwareVersion = + UA_STRING_ALLOC(VERSION(UA_OPEN62541_VER_MAJOR, UA_OPEN62541_VER_MINOR, + UA_OPEN62541_VER_PATCH, UA_OPEN62541_VER_LABEL)); +#ifdef UA_PACK_DEBIAN + conf->buildInfo.buildNumber = UA_STRING_ALLOC("deb"); +#else + conf->buildInfo.buildNumber = UA_STRING_ALLOC(__DATE__ " " __TIME__); +#endif + conf->buildInfo.buildDate = UA_DateTime_now(); - /* Symmetric encryption Algorithm */ + UA_ApplicationDescription_clear(&conf->applicationDescription); + conf->applicationDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI_SERVER); + conf->applicationDescription.productUri = UA_STRING_ALLOC(PRODUCT_URI); + conf->applicationDescription.applicationName = + UA_LOCALIZEDTEXT_ALLOC("en", APPLICATION_NAME); + conf->applicationDescription.applicationType = UA_APPLICATIONTYPE_SERVER; + /* conf->applicationDescription.gatewayServerUri = UA_STRING_NULL; */ + /* conf->applicationDescription.discoveryProfileUri = UA_STRING_NULL; */ + /* conf->applicationDescription.discoveryUrlsSize = 0; */ + /* conf->applicationDescription.discoveryUrls = NULL; */ - UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm = - &symmetricModule->cryptoModule.encryptionAlgorithm; - symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0"); - symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic256Sha256_getLocalKeyLength; - symEncryptionAlgorithm->getLocalBlockSize = UA_SymEn_Basic256Sha256_getLocalBlockSize; - symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic256Sha256_getRemoteKeyLength; - symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic256Sha256_getRemoteBlockSize; - symEncryptionAlgorithm->decrypt = UA_SymEn_Basic256Sha256_decrypt; - symEncryptionAlgorithm->encrypt = UA_SymEn_Basic256Sha256_encrypt; - symEncryptionAlgorithm->getLocalPlainTextBlockSize = - UA_SymEn_Basic256Sha256_getLocalPlainTextBlockSize; +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + UA_MdnsDiscoveryConfiguration_clear(&conf->mdnsConfig); + conf->mdnsInterfaceIP = UA_STRING_NULL; +# if !defined(UA_HAS_GETIFADDR) + conf->mdnsIpAddressList = NULL; + conf->mdnsIpAddressListSize = 0; +# endif +#endif - /* Symmetric signature Algorithm */ + /* Custom DataTypes */ + /* conf->customDataTypesSize = 0; */ + /* conf->customDataTypes = NULL; */ - UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm = - &symmetricModule->cryptoModule.signatureAlgorithm; - symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0"); - symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic256Sha256_getLocalKeyLength; - symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic256Sha256_getRemoteKeyLength; - symSignatureAlgorithm->getRemoteSignatureSize = - UA_SymSig_Basic256Sha256_getRemoteSignatureSize; - symSignatureAlgorithm->verify = UA_SymSig_Basic256Sha256_verify; - symSignatureAlgorithm->sign = UA_SymSig_Basic256Sha256_sign; - symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic256Sha256_getLocalSignatureSize; + /* Networking */ + /* conf->networkLayersSize = 0; */ + /* conf->networkLayers = NULL; */ + /* conf->customHostname = UA_STRING_NULL; */ - retval = UA_Policy_New_Context (policy, localPrivateKey, logger); - if (retval != UA_STATUSCODE_GOOD) { - UA_ByteString_clear (&policy->localCertificate); - return retval; - } - policy->clear = UA_Policy_Clear_Context; + /* Endpoints */ + /* conf->endpoints = {0, NULL}; */ - /* Use the same signature algorithm as the asymmetric component for - certificate signing (see standard) */ - - policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + /* Certificate Verification that accepts every certificate. Can be + * overwritten when the policy is specialized. */ + UA_CertificateVerification_AcceptAll(&conf->certificateVerification); - return UA_STATUSCODE_GOOD; -} + /* * Global Node Lifecycle * */ + /* conf->nodeLifecycle.constructor = NULL; */ + /* conf->nodeLifecycle.destructor = NULL; */ + /* conf->nodeLifecycle.createOptionalChild = NULL; */ + /* conf->nodeLifecycle.generateChildNodeId = NULL; */ + conf->modellingRulesOnInstances = UA_TRUE; -#endif + /* Limits for SecureChannels */ + conf->maxSecureChannels = 40; + conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/securityPolicies/openssl/ua_pki_openssl.c" ***********************************/ + /* Limits for Sessions */ + conf->maxSessions = 100; + conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */ -/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. - * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. - * - * Copyright 2020 (c) Wind River Systems, Inc. - * Copyright 2020 (c) basysKom GmbH +#ifdef UA_ENABLE_SUBSCRIPTIONS + /* Limits for Subscriptions */ + conf->publishingIntervalLimits = UA_DURATIONRANGE(100.0, 3600.0 * 1000.0); + conf->lifeTimeCountLimits = UA_UINT32RANGE(3, 15000); + conf->keepAliveCountLimits = UA_UINT32RANGE(1, 100); + conf->maxNotificationsPerPublish = 1000; + conf->enableRetransmissionQueue = true; + conf->maxRetransmissionQueueSize = 0; /* unlimited */ +# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + conf->maxEventsPerNode = 0; /* unlimited */ +# endif - */ + /* Limits for MonitoredItems */ + conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0); + conf->queueSizeLimits = UA_UINT32RANGE(1, 100); +#endif -/* -modification history --------------------- -21feb20,lan written -*/ +#ifdef UA_ENABLE_DISCOVERY + conf->discoveryCleanupTimeout = 60 * 60; +#endif +#ifdef UA_ENABLE_HISTORIZING + /* conf->accessHistoryDataCapability = UA_FALSE; */ + /* conf->maxReturnDataValues = 0; */ + /* conf->accessHistoryEventsCapability = UA_FALSE; */ + /* conf->maxReturnEventValues = 0; */ -#ifdef UA_ENABLE_ENCRYPTION_OPENSSL -#include <openssl/x509.h> -#include <openssl/x509_vfy.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> + /* conf->insertDataCapability = UA_FALSE; */ + /* conf->insertEventCapability = UA_FALSE; */ + /* conf->insertAnnotationsCapability = UA_FALSE; */ -typedef struct { - /* - * If the folders are defined, we use them to reload the certificates during - * runtime - */ + /* conf->replaceDataCapability = UA_FALSE; */ + /* conf->replaceEventCapability = UA_FALSE; */ - UA_String trustListFolder; - UA_String issuerListFolder; - UA_String revocationListFolder; + /* conf->updateDataCapability = UA_FALSE; */ + /* conf->updateEventCapability = UA_FALSE; */ - STACK_OF(X509) * skIssue; - STACK_OF(X509) * skTrusted; - STACK_OF(X509_CRL) * skCrls; /* Revocation list*/ -} CertContext; + /* conf->deleteRawCapability = UA_FALSE; */ + /* conf->deleteEventCapability = UA_FALSE; */ + /* conf->deleteAtTimeDataCapability = UA_FALSE; */ +#endif + +#if UA_MULTITHREADING >= 100 + conf->maxAsyncOperationQueueSize = 0; + conf->asyncOperationTimeout = 120000; /* Async Operation Timeout in ms (2 minutes) */ +#endif + + /* --> Finish setting the default static config <-- */ -static UA_StatusCode -UA_CertContext_sk_Init (CertContext * context) { - context->skTrusted = sk_X509_new_null(); - context->skIssue = sk_X509_new_null(); - context->skCrls = sk_X509_CRL_new_null(); - if (context->skTrusted == NULL || context->skIssue == NULL || - context->skCrls == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } return UA_STATUSCODE_GOOD; } -static void -UA_CertContext_sk_free (CertContext * context) { - sk_X509_pop_free (context->skTrusted, X509_free); - sk_X509_pop_free (context->skIssue, X509_free); - sk_X509_CRL_pop_free (context->skCrls, X509_CRL_free); +UA_EXPORT UA_StatusCode +UA_ServerConfig_setBasics(UA_ServerConfig* conf) { + UA_StatusCode res = setDefaultConfig(conf); + UA_LOG_WARNING(&conf->logger, UA_LOGCATEGORY_USERLAND, + "AcceptAll Certificate Verification. " + "Any remote certificate will be accepted."); + return res; } -static UA_StatusCode -UA_CertContext_Init (CertContext * context) { - (void) memset (context, 0, sizeof (CertContext)); - UA_ByteString_init (&context->trustListFolder); - UA_ByteString_init (&context->issuerListFolder); - UA_ByteString_init (&context->revocationListFolder); - return UA_CertContext_sk_Init (context); +static UA_StatusCode +addDefaultNetworkLayers(UA_ServerConfig *conf, UA_UInt16 portNumber, + UA_UInt32 sendBufferSize, UA_UInt32 recvBufferSize) { + return UA_ServerConfig_addNetworkLayerTCP(conf, portNumber, sendBufferSize, recvBufferSize); } -static void -UA_CertificateVerification_clear (UA_CertificateVerification * cv) { - if (cv == NULL) { - return ; - } - CertContext * context = (CertContext *) cv->context; - if (context == NULL) { - return; - } - UA_ByteString_deleteMembers (&context->trustListFolder); - UA_ByteString_deleteMembers (&context->issuerListFolder); - UA_ByteString_deleteMembers (&context->revocationListFolder); +#ifdef UA_ENABLE_WEBSOCKET_SERVER +UA_EXPORT UA_StatusCode +UA_ServerConfig_addNetworkLayerWS(UA_ServerConfig *conf, UA_UInt16 portNumber, + UA_UInt32 sendBufferSize, UA_UInt32 recvBufferSize, const UA_ByteString* certificate, const UA_ByteString* privateKey) { + /* Add a network layer */ + UA_ServerNetworkLayer *tmp = (UA_ServerNetworkLayer *) + UA_realloc(conf->networkLayers, + sizeof(UA_ServerNetworkLayer) * (1 + conf->networkLayersSize)); + if(!tmp) + return UA_STATUSCODE_BADOUTOFMEMORY; + conf->networkLayers = tmp; - UA_CertContext_sk_free (context); - UA_free (context); + UA_ConnectionConfig config = UA_ConnectionConfig_default; + if(sendBufferSize > 0) + config.sendBufferSize = sendBufferSize; + if(recvBufferSize > 0) + config.recvBufferSize = recvBufferSize; - cv->context = NULL; + conf->networkLayers[conf->networkLayersSize] = + UA_ServerNetworkLayerWS(config, portNumber, certificate, privateKey); + if(!conf->networkLayers[conf->networkLayersSize].handle) + return UA_STATUSCODE_BADOUTOFMEMORY; + conf->networkLayersSize++; - return; + return UA_STATUSCODE_GOOD; } +#endif -static UA_StatusCode -UA_skTrusted_Cert2X509 (const UA_ByteString * certificateTrustList, - size_t certificateTrustListSize, - CertContext * ctx) { - size_t i; +UA_EXPORT UA_StatusCode +UA_ServerConfig_addNetworkLayerTCP(UA_ServerConfig *conf, UA_UInt16 portNumber, + UA_UInt32 sendBufferSize, UA_UInt32 recvBufferSize) { + /* Add a network layer */ + UA_ServerNetworkLayer *tmp = (UA_ServerNetworkLayer *) + UA_realloc(conf->networkLayers, + sizeof(UA_ServerNetworkLayer) * (1 + conf->networkLayersSize)); + if(!tmp) + return UA_STATUSCODE_BADOUTOFMEMORY; + conf->networkLayers = tmp; - for (i = 0; i < certificateTrustListSize; i++) { - X509 * x509 = UA_OpenSSL_LoadCertificate(&certificateTrustList[i]); + UA_ConnectionConfig config = UA_ConnectionConfig_default; + if (sendBufferSize > 0) + config.sendBufferSize = sendBufferSize; + if (recvBufferSize > 0) + config.recvBufferSize = recvBufferSize; - if (x509 == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; + conf->networkLayers[conf->networkLayersSize] = + UA_ServerNetworkLayerTCP(config, portNumber, 0); + if (!conf->networkLayers[conf->networkLayersSize].handle) + return UA_STATUSCODE_BADOUTOFMEMORY; + conf->networkLayersSize++; + + return UA_STATUSCODE_GOOD; +} + +UA_EXPORT UA_StatusCode +UA_ServerConfig_addSecurityPolicyNone(UA_ServerConfig *config, + const UA_ByteString *certificate) { + /* Allocate the SecurityPolicies */ + UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) + UA_realloc(config->securityPolicies, + sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); + if(!tmp) + return UA_STATUSCODE_BADOUTOFMEMORY; + config->securityPolicies = tmp; + + /* Populate the SecurityPolicies */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + UA_StatusCode retval = + UA_SecurityPolicy_None(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, &config->logger); + if(retval != UA_STATUSCODE_GOOD) { + if(config->securityPoliciesSize == 0) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; } - sk_X509_push (ctx->skTrusted, x509); + return retval; } - return UA_STATUSCODE_GOOD; + config->securityPoliciesSize++; + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_skIssuer_Cert2X509 (const UA_ByteString * certificateIssuerList, - size_t certificateIssuerListSize, - CertContext * ctx) { - size_t i; - - for (i = 0; i < certificateIssuerListSize; i++) { - X509 * x509 = UA_OpenSSL_LoadCertificate(&certificateIssuerList[i]); +UA_EXPORT UA_StatusCode +UA_ServerConfig_addEndpoint(UA_ServerConfig *config, const UA_String securityPolicyUri, + UA_MessageSecurityMode securityMode) { + /* Allocate the endpoint */ + UA_EndpointDescription *tmp = (UA_EndpointDescription *) + UA_realloc(config->endpoints, + sizeof(UA_EndpointDescription) * (1 + config->endpointsSize)); + if(!tmp) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + config->endpoints = tmp; - if (x509 == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; + /* Lookup the security policy */ + const UA_SecurityPolicy *policy = NULL; + for (size_t i = 0; i < config->securityPoliciesSize; ++i) { + if (UA_String_equal(&securityPolicyUri, &config->securityPolicies[i].policyUri)) { + policy = &config->securityPolicies[i]; + break; } - sk_X509_push (ctx->skIssue, x509); } + if (!policy) + return UA_STATUSCODE_BADINVALIDARGUMENT; - return UA_STATUSCODE_GOOD; -} + /* Populate the endpoint */ + UA_StatusCode retval = + createEndpoint(config, &config->endpoints[config->endpointsSize], + policy, securityMode); + if(retval != UA_STATUSCODE_GOOD) + return retval; + config->endpointsSize++; -static UA_StatusCode -UA_skCrls_Cert2X509 (const UA_ByteString * certificateRevocationList, - size_t certificateRevocationListSize, - CertContext * ctx) { - size_t i; - const unsigned char * pData; + return UA_STATUSCODE_GOOD; +} - for (i = 0; i < certificateRevocationListSize; i++) { - pData = certificateRevocationList[i].data; - X509_CRL * crl = NULL; +UA_EXPORT UA_StatusCode +UA_ServerConfig_addAllEndpoints(UA_ServerConfig *config) { + /* Allocate the endpoints */ + UA_EndpointDescription * tmp = (UA_EndpointDescription *) + UA_realloc(config->endpoints, + sizeof(UA_EndpointDescription) * + (2 * config->securityPoliciesSize + config->endpointsSize)); + if(!tmp) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + config->endpoints = tmp; - if (certificateRevocationList[i].length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files - crl = d2i_X509_CRL (NULL, &pData, (long) certificateRevocationList[i].length); + /* Populate the endpoints */ + for(size_t i = 0; i < config->securityPoliciesSize; ++i) { + if(UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &config->securityPolicies[i].policyUri)) { + UA_StatusCode retval = + createEndpoint(config, &config->endpoints[config->endpointsSize], + &config->securityPolicies[i], UA_MESSAGESECURITYMODE_NONE); + if(retval != UA_STATUSCODE_GOOD) + return retval; + config->endpointsSize++; } else { - BIO* bio = NULL; - -#if OPENSSL_VERSION_NUMBER < 0x1000207fL - bio = BIO_new_mem_buf((void *) certificateRevocationList[i].data, - (int) certificateRevocationList[i].length); -#else - bio = BIO_new_mem_buf((const void *) certificateRevocationList[i].data, - (int) certificateRevocationList[i].length); -#endif - crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); - BIO_free(bio); - } + UA_StatusCode retval = + createEndpoint(config, &config->endpoints[config->endpointsSize], + &config->securityPolicies[i], UA_MESSAGESECURITYMODE_SIGN); + if(retval != UA_STATUSCODE_GOOD) + return retval; + config->endpointsSize++; - if (crl == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; + retval = createEndpoint(config, &config->endpoints[config->endpointsSize], + &config->securityPolicies[i], + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT); + if(retval != UA_STATUSCODE_GOOD) + return retval; + config->endpointsSize++; } - sk_X509_CRL_push (ctx->skCrls, crl); } - return UA_STATUSCODE_GOOD; + return UA_STATUSCODE_GOOD; } -#ifdef __linux__ -#include <dirent.h> - -static int UA_Certificate_Filter_der_pem (const struct dirent * entry) { - char *pszFind; +UA_EXPORT UA_StatusCode +UA_ServerConfig_setMinimalCustomBuffer(UA_ServerConfig *config, UA_UInt16 portNumber, + const UA_ByteString *certificate, + UA_UInt32 sendBufferSize, + UA_UInt32 recvBufferSize) { + if(!config) + return UA_STATUSCODE_BADINVALIDARGUMENT; - /* ignore hidden files */ - if (entry->d_name[0] == '.') return 0; + UA_StatusCode retval = setDefaultConfig(config); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(config); + return retval; + } - /* check file extension */ - pszFind = strrchr(entry->d_name, '.'); - if (pszFind == 0) - return 0; - pszFind++; - if (strcmp (pszFind, "der") == 0 || strcmp (pszFind, "pem") == 0) - return 1; + retval = addDefaultNetworkLayers(config, portNumber, sendBufferSize, recvBufferSize); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(config); + return retval; + } - return 0; -} + /* Allocate the SecurityPolicies */ + retval = UA_ServerConfig_addSecurityPolicyNone(config, certificate); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(config); + return retval; + } -static int UA_Certificate_Filter_crl (const struct dirent * entry) { - char *pszFind; + /* Initialize the Access Control plugin */ + retval = UA_AccessControl_default(config, true, NULL, + &config->securityPolicies[config->securityPoliciesSize-1].policyUri, + usernamePasswordsSize, usernamePasswords); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(config); + return retval; + } - /* ignore hidden files */ - if (entry->d_name[0] == '.') return 0; + /* Allocate the endpoint */ + retval = UA_ServerConfig_addEndpoint(config, UA_SECURITY_POLICY_NONE_URI, + UA_MESSAGESECURITYMODE_NONE); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(config); + return retval; + } - /* check file extension */ - pszFind = strrchr(entry->d_name, '.'); - if (pszFind == 0) - return 0; - pszFind++; - if (strcmp (pszFind, "crl") == 0) - return 1; + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "AcceptAll Certificate Verification. " + "Any remote certificate will be accepted."); - return 0; + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_BuildFullPath (const char * path, - const char * fileName, - size_t fullPathBufferLength, - char * fullPath) { - size_t pathLen = strlen (path); - size_t fileNameLen = strlen (fileName); - if ((pathLen + fileNameLen + 2) > fullPathBufferLength) { - return UA_STATUSCODE_BADINVALIDARGUMENT; +#ifdef UA_ENABLE_ENCRYPTION + +UA_EXPORT UA_StatusCode +UA_ServerConfig_addSecurityPolicyBasic128Rsa15(UA_ServerConfig *config, + const UA_ByteString *certificate, + const UA_ByteString *privateKey) { + /* Allocate the SecurityPolicies */ + UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) + UA_realloc(config->securityPolicies, + sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); + if(!tmp) + return UA_STATUSCODE_BADOUTOFMEMORY; + config->securityPolicies = tmp; + + /* Populate the SecurityPolicies */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + if(privateKey) + localPrivateKey = *privateKey; + UA_StatusCode retval = + UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, localPrivateKey, &config->logger); + if(retval != UA_STATUSCODE_GOOD) { + if(config->securityPoliciesSize == 0) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; + } + return retval; } - strcpy (fullPath, path); - strcat (fullPath, "/"); - strcat (fullPath, fileName); + config->securityPoliciesSize++; return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_loadCertFromFile (const char * fileName, - UA_ByteString * cert) { - - FILE * fp = fopen(fileName, "rb"); - - if (fp == NULL) - return UA_STATUSCODE_BADINTERNALERROR; - - fseek(fp, 0, SEEK_END); - cert->length = (size_t) ftell(fp); - if (UA_ByteString_allocBuffer (cert, cert->length) != UA_STATUSCODE_GOOD) { - fclose (fp); +UA_EXPORT UA_StatusCode +UA_ServerConfig_addSecurityPolicyBasic256(UA_ServerConfig *config, + const UA_ByteString *certificate, + const UA_ByteString *privateKey) { + /* Allocate the SecurityPolicies */ + UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) + UA_realloc(config->securityPolicies, + sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); + if(!tmp) return UA_STATUSCODE_BADOUTOFMEMORY; + config->securityPolicies = tmp; + + /* Populate the SecurityPolicies */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + if(privateKey) + localPrivateKey = *privateKey; + UA_StatusCode retval = + UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, localPrivateKey, &config->logger); + if(retval != UA_STATUSCODE_GOOD) { + if(config->securityPoliciesSize == 0) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; + } + return retval; } - fseek(fp, 0, SEEK_SET); - size_t readLen = fread (cert->data, 1, cert->length, fp); - if (readLen != cert->length) { - UA_ByteString_deleteMembers (cert); - cert->length = 0; - fclose (fp); - return UA_STATUSCODE_BADINTERNALERROR; - } - fclose (fp); + config->securityPoliciesSize++; return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_ReloadCertFromFolder (CertContext * ctx) { - UA_StatusCode ret; - struct dirent ** dirlist = NULL; - int i; - int numCertificates; - char certFile[PATH_MAX]; - UA_ByteString strCert; - char folderPath[PATH_MAX]; - - UA_ByteString_init (&strCert); - - if (ctx->trustListFolder.length > 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list"); - - sk_X509_pop_free (ctx->skTrusted, X509_free); - ctx->skTrusted = sk_X509_new_null(); - if (ctx->skTrusted == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; +UA_EXPORT UA_StatusCode +UA_ServerConfig_addSecurityPolicyBasic256Sha256(UA_ServerConfig *config, + const UA_ByteString *certificate, + const UA_ByteString *privateKey) { + /* Allocate the SecurityPolicies */ + UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) + UA_realloc(config->securityPolicies, + sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); + if(!tmp) + return UA_STATUSCODE_BADOUTOFMEMORY; + config->securityPolicies = tmp; + + /* Populate the SecurityPolicies */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + if(privateKey) + localPrivateKey = *privateKey; + UA_StatusCode retval = + UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, localPrivateKey, &config->logger); + if(retval != UA_STATUSCODE_GOOD) { + if(config->securityPoliciesSize == 0) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; } + return retval; + } - (void) memcpy (folderPath, ctx->trustListFolder.data, - ctx->trustListFolder.length); - folderPath[ctx->trustListFolder.length] = 0; - numCertificates = scandir(folderPath, &dirlist, - UA_Certificate_Filter_der_pem, - alphasort); - for (i = 0; i < numCertificates; i++) { - if (UA_BuildFullPath (folderPath, dirlist[i]->d_name, - PATH_MAX, certFile) != UA_STATUSCODE_GOOD) { - continue; - } - ret = UA_loadCertFromFile (certFile, &strCert); - if (ret != UA_STATUSCODE_GOOD) { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to load the certificate file %s", certFile); - continue; /* continue or return ? */ - } - if (UA_skTrusted_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to decode the certificate file %s", certFile); - UA_ByteString_clear (&strCert); - continue; /* continue or return ? */ - } - UA_ByteString_clear (&strCert); + config->securityPoliciesSize++; + return UA_STATUSCODE_GOOD; +} + +UA_EXPORT UA_StatusCode +UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(UA_ServerConfig *config, + const UA_ByteString *certificate, + const UA_ByteString *privateKey) { + /* Allocate the SecurityPolicies */ + UA_SecurityPolicy *tmp = (UA_SecurityPolicy *) + UA_realloc(config->securityPolicies, + sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize)); + if(!tmp) + return UA_STATUSCODE_BADOUTOFMEMORY; + config->securityPolicies = tmp; + + /* Populate the SecurityPolicies */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + if(privateKey) + localPrivateKey = *privateKey; + UA_StatusCode retval = + UA_SecurityPolicy_Aes128Sha256RsaOaep(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, localPrivateKey, &config->logger); + if(retval != UA_STATUSCODE_GOOD) { + if(config->securityPoliciesSize == 0) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; } + return retval; } - if (ctx->issuerListFolder.length > 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list"); + config->securityPoliciesSize++; + return UA_STATUSCODE_GOOD; +} - sk_X509_pop_free (ctx->skIssue, X509_free); - ctx->skIssue = sk_X509_new_null(); - if (ctx->skIssue == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } +/* Always returns UA_STATUSCODE_GOOD. Logs a warning if policies could not be added. */ +UA_EXPORT UA_StatusCode +UA_ServerConfig_addAllSecurityPolicies(UA_ServerConfig *config, + const UA_ByteString *certificate, + const UA_ByteString *privateKey) { + /* Populate the SecurityPolicies */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + UA_ByteString localPrivateKey = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + if(privateKey) + localPrivateKey = *privateKey; - memcpy (folderPath, ctx->issuerListFolder.data, ctx->issuerListFolder.length); - folderPath[ctx->issuerListFolder.length] = 0; - numCertificates = scandir(folderPath, &dirlist, - UA_Certificate_Filter_der_pem, - alphasort); - for (i = 0; i < numCertificates; i++) { - if (UA_BuildFullPath (folderPath, dirlist[i]->d_name, - PATH_MAX, certFile) != UA_STATUSCODE_GOOD) { - continue; - } - ret = UA_loadCertFromFile (certFile, &strCert); - if (ret != UA_STATUSCODE_GOOD) { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to load the certificate file %s", certFile); - continue; /* continue or return ? */ - } - if (UA_skIssuer_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to decode the certificate file %s", certFile); - UA_ByteString_clear (&strCert); - continue; /* continue or return ? */ - } - UA_ByteString_clear (&strCert); - } + UA_StatusCode retval = UA_ServerConfig_addSecurityPolicyNone(config, &localCertificate); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#None with error code %s", + UA_StatusCode_name(retval)); } - if (ctx->revocationListFolder.length > 0) { - UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list"); + retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &localCertificate, &localPrivateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", + UA_StatusCode_name(retval)); + } - sk_X509_CRL_pop_free (ctx->skCrls, X509_CRL_free); - ctx->skCrls = sk_X509_CRL_new_null(); - if (ctx->skCrls == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } + retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &localCertificate, &localPrivateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Basic256 with error code %s", + UA_StatusCode_name(retval)); + } - memcpy (folderPath, ctx->revocationListFolder.data, ctx->revocationListFolder.length); - folderPath[ctx->revocationListFolder.length] = 0; - numCertificates = scandir(folderPath, &dirlist, - UA_Certificate_Filter_crl, - alphasort); - for (i = 0; i < numCertificates; i++) { - if (UA_BuildFullPath (folderPath, dirlist[i]->d_name, - PATH_MAX, certFile) != UA_STATUSCODE_GOOD) { - continue; - } - ret = UA_loadCertFromFile (certFile, &strCert); - if (ret != UA_STATUSCODE_GOOD) { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to load the revocation file %s", certFile); - continue; /* continue or return ? */ - } - if (UA_skCrls_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) { - UA_LOG_INFO (UA_Log_Stdout, UA_LOGCATEGORY_SERVER, - "Failed to decode the revocation file %s", certFile); - UA_ByteString_clear (&strCert); - continue; /* continue or return ? */ - } - UA_ByteString_clear (&strCert); - } + retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &localCertificate, &localPrivateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Basic256Sha256 with error code %s", + UA_StatusCode_name(retval)); } - ret = UA_STATUSCODE_GOOD; - return ret; -} + retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &localCertificate, &localPrivateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s", + UA_StatusCode_name(retval)); + } -#endif /* end of __linux__ */ + return UA_STATUSCODE_GOOD; +} -static UA_StatusCode -UA_X509_Store_CTX_Error_To_UAError (int opensslErr) { - UA_StatusCode ret; - - switch (opensslErr) { - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CRL_NOT_YET_VALID: - case X509_V_ERR_CRL_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: - case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: - ret = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; - break; - case X509_V_ERR_CERT_REVOKED: - ret = UA_STATUSCODE_BADCERTIFICATEREVOKED; - break; - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; - break; - case X509_V_ERR_CERT_SIGNATURE_FAILURE: - ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED ; - break; - default: - ret = UA_STATUSCODE_BADCERTIFICATEINVALID; - break; - } - return ret; +UA_EXPORT UA_StatusCode +UA_ServerConfig_setDefaultWithSecurityPolicies(UA_ServerConfig *conf, + UA_UInt16 portNumber, + const UA_ByteString *certificate, + const UA_ByteString *privateKey, + const UA_ByteString *trustList, + size_t trustListSize, + const UA_ByteString *issuerList, + size_t issuerListSize, + const UA_ByteString *revocationList, + size_t revocationListSize) { + UA_StatusCode retval = setDefaultConfig(conf); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(conf); + return retval; } -static UA_StatusCode -UA_CertificateVerification_Verify (void * verificationContext, - const UA_ByteString * certificate) { - X509_STORE_CTX* storeCtx; - X509_STORE* store; - CertContext * ctx; - UA_StatusCode ret; - int opensslRet; - X509 * certificateX509 = NULL; + retval = UA_CertificateVerification_Trustlist(&conf->certificateVerification, + trustList, trustListSize, + issuerList, issuerListSize, + revocationList, revocationListSize); + if (retval != UA_STATUSCODE_GOOD) + return retval; - if (verificationContext == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; + retval = addDefaultNetworkLayers(conf, portNumber, 0, 0); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(conf); + return retval; } - ctx = (CertContext *) verificationContext; - - store = X509_STORE_new(); - storeCtx = X509_STORE_CTX_new(); - - if (store == NULL || storeCtx == NULL) { - ret = UA_STATUSCODE_BADOUTOFMEMORY; - goto cleanup; + + retval = UA_ServerConfig_addAllSecurityPolicies(conf, certificate, privateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(conf); + return retval; } -#ifdef __linux__ - ret = UA_ReloadCertFromFolder (ctx); - if (ret != UA_STATUSCODE_GOOD) { - goto cleanup; + + UA_CertificateVerification accessControlVerification; + retval = UA_CertificateVerification_Trustlist(&accessControlVerification, + trustList, trustListSize, + issuerList, issuerListSize, + revocationList, revocationListSize); + retval |= UA_AccessControl_default(conf, true, &accessControlVerification, + &conf->securityPolicies[conf->securityPoliciesSize-1].policyUri, + usernamePasswordsSize, usernamePasswords); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(conf); + return retval; } -#endif - certificateX509 = UA_OpenSSL_LoadCertificate(certificate); - if (certificateX509 == NULL) { - ret = UA_STATUSCODE_BADCERTIFICATEINVALID; - goto cleanup; - } + retval = UA_ServerConfig_addAllEndpoints(conf); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_clean(conf); + return retval; + } - X509_STORE_set_flags(store, 0); - opensslRet = X509_STORE_CTX_init (storeCtx, store, certificateX509, - ctx->skIssue); - if (opensslRet != 1) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto cleanup; + return UA_STATUSCODE_GOOD; +} + +#endif + +/***************************/ +/* Default Client Settings */ +/***************************/ + +UA_Client * UA_Client_new(void) { + UA_ClientConfig config; + memset(&config, 0, sizeof(UA_ClientConfig)); + config.logger.log = UA_Log_Stdout_log; + config.logger.context = NULL; + config.logger.clear = UA_Log_Stdout_clear; + return UA_Client_newWithConfig(&config); +} + +UA_StatusCode +UA_ClientConfig_setDefault(UA_ClientConfig *config) { + config->timeout = 5000; + config->secureChannelLifeTime = 10 * 60 * 1000; /* 10 minutes */ + + if(!config->logger.log) { + config->logger.log = UA_Log_Stdout_log; + config->logger.context = NULL; + config->logger.clear = UA_Log_Stdout_clear; } - (void) X509_STORE_CTX_trusted_stack (storeCtx, ctx->skTrusted); - /* Set crls to ctx */ - if (sk_X509_CRL_num (ctx->skCrls) > 0) { - X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls); + if (config->sessionLocaleIdsSize > 0 && config->sessionLocaleIds) { + UA_Array_delete(config->sessionLocaleIds, config->sessionLocaleIdsSize, &UA_TYPES[UA_TYPES_LOCALEID]); } + config->sessionLocaleIds = NULL; + config->sessionLocaleIds = 0; + + config->localConnectionConfig = UA_ConnectionConfig_default; -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL - if (X509_STORE_CTX_get_check_issued (storeCtx) (storeCtx,certificateX509, certificateX509) != 1) { - X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + /* Certificate Verification that accepts every certificate. Can be + * overwritten when the policy is specialized. */ + UA_CertificateVerification_AcceptAll(&config->certificateVerification); + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "AcceptAll Certificate Verification. " + "Any remote certificate will be accepted."); + + /* With encryption enabled, the applicationUri needs to match the URI from + * the certificate */ + config->clientDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI); + config->clientDescription.applicationType = UA_APPLICATIONTYPE_CLIENT; + + if(config->securityPoliciesSize > 0) { + UA_LOG_ERROR(&config->logger, UA_LOGCATEGORY_NETWORK, + "Could not initialize a config that already has SecurityPolicies"); + return UA_STATUSCODE_BADINTERNALERROR; } -#else - if (storeCtx->check_issued(storeCtx,certificateX509, certificateX509) != 1) { - X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + + config->securityPolicies = (UA_SecurityPolicy*)UA_malloc(sizeof(UA_SecurityPolicy)); + if(!config->securityPolicies) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_StatusCode retval = UA_SecurityPolicy_None(config->securityPolicies, + UA_BYTESTRING_NULL, &config->logger); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; + return retval; } -#endif + config->securityPoliciesSize = 1; - opensslRet = X509_verify_cert (storeCtx); - if (opensslRet == 1) { - ret = UA_STATUSCODE_GOOD; + config->initConnectionFunc = UA_ClientConnectionTCP_init; /* for async client */ + config->pollConnectionFunc = UA_ClientConnectionTCP_poll; /* for async connection */ + + config->customDataTypes = NULL; + config->stateCallback = NULL; + config->connectivityCheckInterval = 0; + + config->requestedSessionTimeout = 1200000; /* requestedSessionTimeout */ + + config->inactivityCallback = NULL; + config->clientContext = NULL; + +#ifdef UA_ENABLE_SUBSCRIPTIONS + config->outStandingPublishRequests = 10; + config->subscriptionInactivityCallback = NULL; +#endif + + return UA_STATUSCODE_GOOD; +} + +#ifdef UA_ENABLE_ENCRYPTION +UA_StatusCode +UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config, + UA_ByteString localCertificate, UA_ByteString privateKey, + const UA_ByteString *trustList, size_t trustListSize, + const UA_ByteString *revocationList, size_t revocationListSize) { + UA_StatusCode retval = UA_ClientConfig_setDefault(config); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + retval = UA_CertificateVerification_Trustlist(&config->certificateVerification, + trustList, trustListSize, + NULL, 0, + revocationList, revocationListSize); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Populate SecurityPolicies */ + UA_SecurityPolicy *sp = (UA_SecurityPolicy*) + UA_realloc(config->securityPolicies, sizeof(UA_SecurityPolicy) * 5); + if(!sp) + return UA_STATUSCODE_BADOUTOFMEMORY; + config->securityPolicies = sp; + + retval = UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, privateKey, &config->logger); + if(retval == UA_STATUSCODE_GOOD) { + ++config->securityPoliciesSize; + } else { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Basic128Rsa15 with error code %s", + UA_StatusCode_name(retval)); } - else { - /* Return opc founcation CTT tool expected error */ - opensslRet = X509_STORE_CTX_get_error (storeCtx); - ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet); + + retval = UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, privateKey, &config->logger); + if(retval == UA_STATUSCODE_GOOD) { + ++config->securityPoliciesSize; + } else { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Basic256 with error code %s", + UA_StatusCode_name(retval)); } -cleanup: - if (store != NULL) { - X509_STORE_free (store); + + retval = UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, privateKey, &config->logger); + if(retval == UA_STATUSCODE_GOOD) { + ++config->securityPoliciesSize; + } else { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Basic256Sha256 with error code %s", + UA_StatusCode_name(retval)); } - if (storeCtx != NULL) { - X509_STORE_CTX_free (storeCtx); + + retval = UA_SecurityPolicy_Aes128Sha256RsaOaep(&config->securityPolicies[config->securityPoliciesSize], + localCertificate, privateKey, &config->logger); + if(retval == UA_STATUSCODE_GOOD) { + ++config->securityPoliciesSize; + } else { + UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND, + "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s", + UA_StatusCode_name(retval)); } - if (certificateX509 != NULL) { - X509_free (certificateX509); + + if(config->securityPoliciesSize == 0) { + UA_free(config->securityPolicies); + config->securityPolicies = NULL; } - return ret; + + return UA_STATUSCODE_GOOD; } +#endif + +/**** amalgamated original file "/plugins/crypto/ua_pki_none.c" ****/ + +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2020 (c) Julius Pfrommer, Fraunhofer IOSB + */ + static UA_StatusCode -UA_VerifyCertificateAllowAll (void * verificationContext, - const UA_ByteString * certificate) { - (void) verificationContext; - (void) certificate; - return UA_STATUSCODE_GOOD; +verifyCertificateAllowAll(void *verificationContext, + const UA_ByteString *certificate) { + return UA_STATUSCODE_GOOD; } -static UA_StatusCode -UA_CertificateVerification_VerifyApplicationURI (void * verificationContext, - const UA_ByteString * certificate, - const UA_String * applicationURI) { - (void) verificationContext; +static UA_StatusCode +verifyApplicationURIAllowAll(void *verificationContext, + const UA_ByteString *certificate, + const UA_String *applicationURI) { + return UA_STATUSCODE_GOOD; +} - const unsigned char * pData; - X509 * certificateX509; - UA_String subjectURI; - GENERAL_NAMES * pNames; - int i; - UA_StatusCode ret; - - pData = certificate->data; - if (pData == NULL) { - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } +static void +clearVerifyAllowAll(UA_CertificateVerification *cv) { - certificateX509 = UA_OpenSSL_LoadCertificate(certificate); - if (certificateX509 == NULL) { - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } +} - pNames = (GENERAL_NAMES *) X509_get_ext_d2i(certificateX509, NID_subject_alt_name, - NULL, NULL); - if (pNames == NULL) { - X509_free (certificateX509); - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - for (i = 0; i < sk_GENERAL_NAME_num (pNames); i++) { - GENERAL_NAME * value = sk_GENERAL_NAME_value (pNames, i); - if (value->type == GEN_URI) { - subjectURI.length = (size_t) (value->d.ia5->length); - subjectURI.data = (UA_Byte *) UA_malloc (subjectURI.length); - if (subjectURI.data == NULL) { - X509_free (certificateX509); - sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free); - return UA_STATUSCODE_BADSECURITYCHECKSFAILED; - } - (void) memcpy (subjectURI.data, value->d.ia5->data, subjectURI.length); - break; - } - - } +void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) { + cv->verifyCertificate = verifyCertificateAllowAll; + cv->verifyApplicationURI = verifyApplicationURIAllowAll; + cv->clear = clearVerifyAllowAll; +} - ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED; - if (UA_Bstrstr (subjectURI.data, subjectURI.length, - applicationURI->data, applicationURI->length) != NULL) { - ret = UA_STATUSCODE_GOOD; - } +/**** amalgamated original file "/plugins/crypto/ua_securitypolicy_none.c" ****/ - X509_free (certificateX509); - sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free); - UA_String_clear (&subjectURI); - return ret; +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS +#endif + +#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) +#endif + +static UA_StatusCode +verify_none(void *channelContext, + const UA_ByteString *message, + const UA_ByteString *signature) { + return UA_STATUSCODE_GOOD; } -/* main entry */ +static UA_StatusCode +sign_none(void *channelContext, const UA_ByteString *message, + UA_ByteString *signature) { + return UA_STATUSCODE_GOOD; +} -UA_StatusCode -UA_CertificateVerification_Trustlist(UA_CertificateVerification * cv, - const UA_ByteString * certificateTrustList, - size_t certificateTrustListSize, - const UA_ByteString * certificateIssuerList, - size_t certificateIssuerListSize, - const UA_ByteString * certificateRevocationList, - size_t certificateRevocationListSize) { - UA_StatusCode ret; +static size_t +length_none(const void *channelContext) { + return 0; +} - if (cv == NULL) { +static UA_StatusCode +encrypt_none(void *channelContext, UA_ByteString *data) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +decrypt_none(void *channelContext, UA_ByteString *data) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +makeThumbprint_none(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificate, + UA_ByteString *thumbprint) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +compareThumbprint_none(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +generateKey_none(void *policyContext, const UA_ByteString *secret, + const UA_ByteString *seed, UA_ByteString *out) { + return UA_STATUSCODE_GOOD; +} + +/* Use the non-cryptographic RNG to set the nonce */ +static UA_StatusCode +generateNonce_none(void *policyContext, UA_ByteString *out) { + if(out == NULL) return UA_STATUSCODE_BADINTERNALERROR; - } - CertContext * context = (CertContext *) UA_malloc (sizeof (CertContext)); - if (context == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } - ret = UA_CertContext_Init (context); - if (ret != UA_STATUSCODE_GOOD) { - return ret; - } + if(out->length == 0) + return UA_STATUSCODE_GOOD; - cv->verifyApplicationURI = UA_CertificateVerification_VerifyApplicationURI; - cv->clear = UA_CertificateVerification_clear; - cv->context = context; - if (certificateTrustListSize > 0) - cv->verifyCertificate = UA_CertificateVerification_Verify; - else - cv->verifyCertificate = UA_VerifyCertificateAllowAll; - - if (certificateTrustListSize > 0) { - if (UA_skTrusted_Cert2X509 (certificateTrustList, certificateTrustListSize, - context) != UA_STATUSCODE_GOOD) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } + /* Fill blocks of four byte */ + size_t i = 0; + while(i + 3 < out->length) { + UA_UInt32 randNumber = UA_UInt32_random(); + memcpy(&out->data[i], &randNumber, 4); + i = i+4; } - if (certificateIssuerListSize > 0) { - if (UA_skIssuer_Cert2X509 (certificateIssuerList, certificateIssuerListSize, - context) != UA_STATUSCODE_GOOD) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - } + /* Fill the remaining byte */ + UA_UInt32 randNumber = UA_UInt32_random(); + memcpy(&out->data[i], &randNumber, out->length % 4); - if (certificateRevocationListSize > 0) { - if (UA_skCrls_Cert2X509 (certificateRevocationList, certificateRevocationListSize, - context) != UA_STATUSCODE_GOOD) { - ret = UA_STATUSCODE_BADINTERNALERROR; - goto errout; - } - } + return UA_STATUSCODE_GOOD; +} +static UA_StatusCode +newContext_none(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **channelContext) { return UA_STATUSCODE_GOOD; +} -errout: - UA_CertificateVerification_clear (cv); - return ret; +static void +deleteContext_none(void *channelContext) { +} + +static UA_StatusCode +setContextValue_none(void *channelContext, + const UA_ByteString *key) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +compareCertificate_none(const void *channelContext, + const UA_ByteString *certificate) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +updateCertificateAndPrivateKey_none(UA_SecurityPolicy *policy, + const UA_ByteString newCertificate, + const UA_ByteString newPrivateKey) { + UA_ByteString_clear(&policy->localCertificate); + UA_ByteString_copy(&newCertificate, &policy->localCertificate); + return UA_STATUSCODE_GOOD; +} + + +static void +policy_clear_none(UA_SecurityPolicy *policy) { + UA_ByteString_clear(&policy->localCertificate); } -#ifdef __linux__ /* Linux only so far */ UA_StatusCode -UA_CertificateVerification_CertFolders(UA_CertificateVerification * cv, - const char * trustListFolder, - const char * issuerListFolder, - const char * revocationListFolder) { - UA_StatusCode ret; - if (cv == NULL) { - return UA_STATUSCODE_BADINTERNALERROR; - } +UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate, + const UA_Logger *logger) { + policy->policyContext = (void *)(uintptr_t)logger; + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); + policy->logger = logger; - CertContext * context = (CertContext *) UA_malloc (sizeof (CertContext)); - if (context == NULL) { - return UA_STATUSCODE_BADOUTOFMEMORY; - } - ret = UA_CertContext_Init (context); - if (ret != UA_STATUSCODE_GOOD) { - return ret; - } +#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS + UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate); +#elif defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) + UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate); +#else + UA_ByteString_copy(&localCertificate, &policy->localCertificate); +#endif - cv->verifyApplicationURI = UA_CertificateVerification_VerifyApplicationURI; - cv->clear = UA_CertificateVerification_clear; - cv->context = context; - cv->verifyCertificate = UA_CertificateVerification_Verify; + policy->symmetricModule.generateKey = generateKey_none; + policy->symmetricModule.generateNonce = generateNonce_none; - /* Only set the folder paths. They will be reloaded during runtime. */ + UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm = + &policy->symmetricModule.cryptoModule.signatureAlgorithm; + sym_signatureAlgorithm->uri = UA_STRING_NULL; + sym_signatureAlgorithm->verify = verify_none; + sym_signatureAlgorithm->sign = sign_none; + sym_signatureAlgorithm->getLocalSignatureSize = length_none; + sym_signatureAlgorithm->getRemoteSignatureSize = length_none; + sym_signatureAlgorithm->getLocalKeyLength = length_none; + sym_signatureAlgorithm->getRemoteKeyLength = length_none; - context->trustListFolder = UA_STRING_ALLOC(trustListFolder); - context->issuerListFolder = UA_STRING_ALLOC(issuerListFolder); - context->revocationListFolder = UA_STRING_ALLOC(revocationListFolder); + UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = + &policy->symmetricModule.cryptoModule.encryptionAlgorithm; + sym_encryptionAlgorithm->uri = UA_STRING_NULL; + sym_encryptionAlgorithm->encrypt = encrypt_none; + sym_encryptionAlgorithm->decrypt = decrypt_none; + sym_encryptionAlgorithm->getLocalKeyLength = length_none; + sym_encryptionAlgorithm->getRemoteKeyLength = length_none; + sym_encryptionAlgorithm->getRemoteBlockSize = length_none; + sym_encryptionAlgorithm->getRemotePlainTextBlockSize = length_none; + policy->symmetricModule.secureChannelNonceLength = 0; + + policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none; + policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none; + + // This only works for none since symmetric and asymmetric crypto modules do the same i.e. nothing + policy->asymmetricModule.cryptoModule = policy->symmetricModule.cryptoModule; + + // Use the same signing algorithm as for asymmetric signing + policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + + policy->channelModule.newContext = newContext_none; + policy->channelModule.deleteContext = deleteContext_none; + policy->channelModule.setLocalSymEncryptingKey = setContextValue_none; + policy->channelModule.setLocalSymSigningKey = setContextValue_none; + policy->channelModule.setLocalSymIv = setContextValue_none; + policy->channelModule.setRemoteSymEncryptingKey = setContextValue_none; + policy->channelModule.setRemoteSymSigningKey = setContextValue_none; + policy->channelModule.setRemoteSymIv = setContextValue_none; + policy->channelModule.compareCertificate = compareCertificate_none; + policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_none; + policy->clear = policy_clear_none; return UA_STATUSCODE_GOOD; } + +/**** amalgamated original file "/plugins/ua_log_syslog.c" ****/ + +/* This work is licensed under a Creative Commons CCZero 1.0 Universal License. + * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. + * + * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + + +#if defined(__linux__) || defined(__unix__) + +#include <syslog.h> + +const char *syslogLevelNames[6] = {"trace", "debug", "info", + "warn", "error", "fatal"}; +const char *syslogCategoryNames[7] = {"network", "channel", "session", "server", + "client", "userland", "securitypolicy"}; + +#ifdef __clang__ +__attribute__((__format__(__printf__, 4 , 0))) #endif +static void +UA_Log_Syslog_log(void *context, UA_LogLevel level, UA_LogCategory category, + const char *msg, va_list args) { + /* Assume that context is casted to UA_LogLevel */ + if(context != NULL && (UA_LogLevel)(uintptr_t)context > level) + return; -#endif /* end of UA_ENABLE_ENCRYPTION_OPENSSL */ + int priority = LOG_INFO; + switch(level) { + case UA_LOGLEVEL_DEBUG: + priority = LOG_DEBUG; + break; + case UA_LOGLEVEL_INFO: + priority = LOG_INFO; + break; + case UA_LOGLEVEL_WARNING: + priority = LOG_WARNING; + break; + case UA_LOGLEVEL_ERROR: + priority = LOG_ERR; + break; + case UA_LOGLEVEL_FATAL: + priority = LOG_CRIT; + break; + case UA_LOGLEVEL_TRACE: + default: + return; + } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/historydata/ua_history_data_backend_memory.c" ***********************************/ +#define LOGBUFSIZE 512 + char logbuf[LOGBUFSIZE]; + int pos = snprintf(logbuf, LOGBUFSIZE, "[%s/%s] ", + syslogLevelNames[level], syslogCategoryNames[category]); + if(pos < 0) { + syslog(LOG_WARNING, "Log message too long for syslog"); + return; + } + pos = vsnprintf(&logbuf[pos], LOGBUFSIZE - (size_t)pos, msg, args); + if(pos < 0) { + syslog(LOG_WARNING, "Log message too long for syslog"); + return; + } + + syslog(priority, "%s", logbuf); +} + +static void +UA_Log_Syslog_clear(void *logContext) { + /* closelog is optional. We don't use it as several loggers might be + * instantiated in parallel. */ + /* closelog(); */ +} + +UA_Logger +UA_Log_Syslog(void) { + return UA_Log_Syslog_withLevel(UA_LOGLEVEL_TRACE); +} + +UA_Logger +UA_Log_Syslog_withLevel(UA_LogLevel minlevel) { + UA_Logger logger = {UA_Log_Syslog_log, (void*)minlevel, UA_Log_Syslog_clear}; + return logger; +} + +#endif + +/**** amalgamated original file "/plugins/historydata/ua_history_data_backend_memory.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -65084,9 +73727,9 @@ typedef struct { } UA_DataValueMemoryStoreItem; static void -UA_DataValueMemoryStoreItem_deleteMembers(UA_DataValueMemoryStoreItem* item) { - UA_DateTime_deleteMembers(&item->timestamp); - UA_DataValue_deleteMembers(&item->value); +UA_DataValueMemoryStoreItem_clear(UA_DataValueMemoryStoreItem* item) { + UA_DateTime_clear(&item->timestamp); + UA_DataValue_clear(&item->value); } typedef struct { @@ -65097,10 +73740,10 @@ typedef struct { } UA_NodeIdStoreContextItem_backend_memory; static void -UA_NodeIdStoreContextItem_deleteMembers(UA_NodeIdStoreContextItem_backend_memory* item) { - UA_NodeId_deleteMembers(&item->nodeId); +UA_NodeIdStoreContextItem_clear(UA_NodeIdStoreContextItem_backend_memory* item) { + UA_NodeId_clear(&item->nodeId); for (size_t i = 0; i < item->storeEnd; ++i) { - UA_DataValueMemoryStoreItem_deleteMembers(item->dataStore[i]); + UA_DataValueMemoryStoreItem_clear(item->dataStore[i]); UA_free(item->dataStore[i]); } UA_free(item->dataStore); @@ -65114,9 +73757,9 @@ typedef struct { } UA_MemoryStoreContext; static void -UA_MemoryStoreContext_deleteMembers(UA_MemoryStoreContext* ctx) { +UA_MemoryStoreContext_clear(UA_MemoryStoreContext* ctx) { for (size_t i = 0; i < ctx->storeEnd; ++i) { - UA_NodeIdStoreContextItem_deleteMembers(&ctx->dataStore[i]); + UA_NodeIdStoreContextItem_clear(&ctx->dataStore[i]); } UA_free(ctx->dataStore); memset(ctx, 0, sizeof(UA_MemoryStoreContext)); @@ -65142,7 +73785,7 @@ getNewNodeIdContext_backend_memory(UA_MemoryStoreContext* context, UA_NodeId_copy(nodeId, &item->nodeId); UA_DataValueMemoryStoreItem ** store = (UA_DataValueMemoryStoreItem **)UA_calloc(ctx->initialStoreSize, sizeof(UA_DataValueMemoryStoreItem*)); if (!store) { - UA_NodeIdStoreContextItem_deleteMembers(item); + UA_NodeIdStoreContextItem_clear(item); return NULL; } item->dataStore = store; @@ -65299,7 +73942,7 @@ serverSetHistoryData_backend_memory(UA_Server *server, static void UA_MemoryStoreContext_delete(UA_MemoryStoreContext* ctx) { - UA_MemoryStoreContext_deleteMembers(ctx); + UA_MemoryStoreContext_clear(ctx); UA_free(ctx); } @@ -65309,7 +73952,7 @@ getEnd_backend_memory(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId * nodeId) { - const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);; + const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId); return item->storeEnd; } @@ -65319,7 +73962,7 @@ lastIndex_backend_memory(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId * nodeId) { - const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);; + const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId); if (item->storeEnd == 0) return 0; return item->storeEnd - 1; @@ -65350,7 +73993,7 @@ timestampsToReturnSupported_backend_memory(UA_Server *server, void *sessionContext, const UA_NodeId *nodeId, const UA_TimestampsToReturn timestampsToReturn) { - const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);; + const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId); if (item->storeEnd == 0) { return true; } @@ -65374,7 +74017,7 @@ getDataValue_backend_memory(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId * nodeId, size_t index) { - const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);; + const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId); return &item->dataStore[index]->value; } @@ -65413,7 +74056,7 @@ copyDataValues_backend_memory(UA_Server *server, return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID; } } - const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);; + const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId); size_t index = startIndex; size_t counter = 0; size_t skipedValues = 0; @@ -65521,7 +74164,7 @@ replaceDataValue_backend_memory(UA_Server *server, MATCH_EQUAL); if (index == item->storeEnd) return UA_STATUSCODE_BADNOENTRYEXISTS; - UA_DataValue_deleteMembers(&item->dataStore[index]->value); + UA_DataValue_clear(&item->dataStore[index]->value); UA_DataValue_copy(value, &item->dataStore[index]->value); return UA_STATUSCODE_GOOD; } @@ -65606,7 +74249,7 @@ removeDataValue_backend_memory(UA_Server *server, } #ifndef __clang_analyzer__ for (size_t i = index1; i < index2; ++i) { - UA_DataValueMemoryStoreItem_deleteMembers(item->dataStore[i]); + UA_DataValueMemoryStoreItem_clear(item->dataStore[i]); UA_free(item->dataStore[i]); } memmove(&item->dataStore[index1], &item->dataStore[index2], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index2)); @@ -65623,7 +74266,8 @@ deleteMembers_backend_memory(UA_HistoryDataBackend *backend) { if (backend == NULL || backend->context == NULL) return; - UA_MemoryStoreContext_deleteMembers((UA_MemoryStoreContext*)backend->context); + UA_MemoryStoreContext_clear((UA_MemoryStoreContext*)backend->context); + UA_free(backend->context); } @@ -65664,14 +74308,14 @@ UA_HistoryDataBackend_Memory(size_t initialNodeIdStoreSize, size_t initialDataSt } void -UA_HistoryDataBackend_Memory_deleteMembers(UA_HistoryDataBackend *backend) +UA_HistoryDataBackend_Memory_clear(UA_HistoryDataBackend *backend) { UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)backend->context; UA_MemoryStoreContext_delete(ctx); memset(backend, 0, sizeof(UA_HistoryDataBackend)); } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/historydata/ua_history_data_gathering_default.c" ***********************************/ +/**** amalgamated original file "/plugins/historydata/ua_history_data_gathering_default.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -65801,6 +74445,7 @@ registerNodeId_gathering_default(UA_Server *server, ctx->storeSize = 0; return UA_STATUSCODE_BADOUTOFMEMORY; } + memset(&ctx->dataStore[ctx->storeSize], 0, (newStoreSize - ctx->storeSize) * sizeof(UA_NodeIdStoreContextItem_gathering_default)); ctx->storeSize = newStoreSize; } UA_NodeId_copy(nodeId, &ctx->dataStore[ctx->storeEnd].nodeId); @@ -65830,7 +74475,7 @@ deleteMembers_gathering_default(UA_HistoryDataGathering *gathering) return; UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)gathering->context; for (size_t i = 0; i < ctx->storeEnd; ++i) { - UA_NodeId_deleteMembers(&ctx->dataStore[i].nodeId); + UA_NodeId_clear(&ctx->dataStore[i].nodeId); // There is still a monitored item present for this gathering // You need to remove it with UA_Server_deleteMonitoredItem UA_assert(ctx->dataStore[i].monitoredResult.monitoredItemId == 0); @@ -65900,7 +74545,7 @@ UA_HistoryDataGathering_Default(size_t initialNodeIdStoreSize) return gathering; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/plugins/historydata/ua_history_database_default.c" ***********************************/ +/**** amalgamated original file "/plugins/historydata/ua_history_database_default.c" ****/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -66192,7 +74837,7 @@ getHistoryData_service_default(const UA_HistoryDataBackend* backend, if(backendOutContinuationPoint.length > 0) memcpy(outContinuationPoint->data + sizeof(size_t), backendOutContinuationPoint.data, backendOutContinuationPoint.length); } - UA_ByteString_deleteMembers(&backendOutContinuationPoint); + UA_ByteString_clear(&backendOutContinuationPoint); return UA_STATUSCODE_GOOD; } @@ -66233,15 +74878,14 @@ updateData_service_default(UA_Server *server, return; } + UA_ServerConfig *config = UA_Server_getConfig(server); result->operationResultsSize = details->updateValuesSize; result->operationResults = (UA_StatusCode*)UA_Array_new(result->operationResultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); for (size_t i = 0; i < details->updateValuesSize; ++i) { - if (!UA_Server_AccessControl_allowHistoryUpdateUpdateData(server, - sessionId, - sessionContext, - &details->nodeId, - details->performInsertReplace, - &details->updateValues[i])) { + if (config->accessControl.allowHistoryUpdateUpdateData && + !config->accessControl.allowHistoryUpdateUpdateData(server, &config->accessControl, sessionId, sessionContext, + &details->nodeId, details->performInsertReplace, + &details->updateValues[i])) { result->operationResults[i] = UA_STATUSCODE_BADUSERACCESSDENIED; continue; } @@ -66338,13 +74982,11 @@ deleteRawModified_service_default(UA_Server *server, return; } - if (!UA_Server_AccessControl_allowHistoryUpdateDeleteRawModified(server, - sessionId, - sessionContext, - &details->nodeId, - details->startTime, - details->endTime, - details->isDeleteModified)) { + UA_ServerConfig *config = UA_Server_getConfig(server); + if (config->accessControl.allowHistoryUpdateDeleteRawModified && + !config->accessControl.allowHistoryUpdateDeleteRawModified(server, + &config->accessControl, sessionId, sessionContext, &details->nodeId, + details->startTime, details->endTime, details->isDeleteModified)) { result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED; return; } @@ -66531,7 +75173,7 @@ UA_HistoryDatabase_default(UA_HistoryDataGathering gathering) return hdb; } -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/arch/posix/ua_clock.c" ***********************************/ +/**** amalgamated original file "/arch/posix/ua_clock.c" ****/ /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. @@ -66545,7 +75187,6 @@ UA_HistoryDatabase_default(UA_HistoryDataGathering gathering) #include <time.h> - #include <sys/time.h> #if defined(__APPLE__) || defined(__MACH__) @@ -66593,7 +75234,7 @@ UA_DateTime UA_DateTime_nowMonotonic(void) { #endif /* UA_ARCHITECTURE_POSIX */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/arch/posix/ua_architecture_functions.c" ***********************************/ +/**** amalgamated original file "/arch/posix/ua_architecture_functions.c" ****/ /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. @@ -66606,10 +75247,10 @@ UA_DateTime UA_DateTime_nowMonotonic(void) { /* Global malloc singletons */ #ifdef UA_ENABLE_MALLOC_SINGLETON -void * (*UA_globalMalloc)(size_t size) = malloc; -void (*UA_globalFree)(void *ptr) = free; -void * (*UA_globalCalloc)(size_t nelem, size_t elsize) = calloc; -void * (*UA_globalRealloc)(void *ptr, size_t size) = realloc; +UA_EXPORT UA_THREAD_LOCAL void * (*UA_mallocSingleton)(size_t size) = malloc; +UA_EXPORT UA_THREAD_LOCAL void (*UA_freeSingleton)(void *ptr) = free; +UA_EXPORT UA_THREAD_LOCAL void * (*UA_callocSingleton)(size_t nelem, size_t elsize) = calloc; +UA_EXPORT UA_THREAD_LOCAL void * (*UA_reallocSingleton)(void *ptr, size_t size) = realloc; #endif unsigned int UA_socket_set_blocking(UA_SOCKET sockfd){ @@ -66634,7 +75275,7 @@ void UA_deinitialize_architecture_network(void){ #endif /* UA_ARCHITECTURE_POSIX */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/arch/win32/ua_clock.c" ***********************************/ +/**** amalgamated original file "/arch/win32/ua_clock.c" ****/ /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. @@ -66683,7 +75324,11 @@ UA_Int64 UA_DateTime_localTimeUtcOffset(void) { time_t gmt, rawtime = time(NULL); struct tm ptm; +#ifdef __CODEGEARC__ + gmtime_s(&rawtime, &ptm); +#else gmtime_s(&ptm, &rawtime); +#endif // Request that mktime() looksup dst in timezone database ptm.tm_isdst = -1; gmt = mktime(&ptm); @@ -66701,7 +75346,7 @@ UA_DateTime UA_DateTime_nowMonotonic(void) { #endif /* UA_ARCHITECTURE_WIN32 */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/arch/win32/ua_architecture_functions.c" ***********************************/ +/**** amalgamated original file "/arch/win32/ua_architecture_functions.c" ****/ /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. @@ -66712,18 +75357,26 @@ UA_DateTime UA_DateTime_nowMonotonic(void) { #ifdef UA_ARCHITECTURE_WIN32 +/* Global malloc singletons */ +#ifdef UA_ENABLE_MALLOC_SINGLETON +UA_EXPORT UA_THREAD_LOCAL void * (*UA_mallocSingleton)(size_t size) = malloc; +UA_EXPORT UA_THREAD_LOCAL void (*UA_freeSingleton)(void *ptr) = free; +UA_EXPORT UA_THREAD_LOCAL void * (*UA_callocSingleton)(size_t nelem, size_t elsize) = calloc; +UA_EXPORT UA_THREAD_LOCAL void * (*UA_reallocSingleton)(void *ptr, size_t size) = realloc; +#endif + unsigned int UA_socket_set_blocking(UA_SOCKET sockfd){ u_long iMode = 0; if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR) return UA_STATUSCODE_BADINTERNALERROR; - return UA_STATUSCODE_GOOD;; + return UA_STATUSCODE_GOOD; } unsigned int UA_socket_set_nonblocking(UA_SOCKET sockfd){ u_long iMode = 1; if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR) return UA_STATUSCODE_BADINTERNALERROR; - return UA_STATUSCODE_GOOD;; + return UA_STATUSCODE_GOOD; } void UA_initialize_architecture_network(void){ @@ -66737,7 +75390,7 @@ void UA_deinitialize_architecture_network(void){ #endif /* UA_ARCHITECTURE_WIN32 */ -/*********************************** amalgamated original file "/home/pdie/sonstiges/qtopcua/repos/open62541/arch/network_tcp.c" ***********************************/ +/**** amalgamated original file "/arch/network_tcp.c" ****/ /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. @@ -66776,19 +75429,19 @@ connection_getsendbuffer(UA_Connection *connection, static void connection_releasesendbuffer(UA_Connection *connection, UA_ByteString *buf) { - UA_ByteString_deleteMembers(buf); + UA_ByteString_clear(buf); } static void connection_releaserecvbuffer(UA_Connection *connection, UA_ByteString *buf) { - UA_ByteString_deleteMembers(buf); + UA_ByteString_clear(buf); } static UA_StatusCode connection_write(UA_Connection *connection, UA_ByteString *buf) { if(connection->state == UA_CONNECTIONSTATE_CLOSED) { - UA_ByteString_deleteMembers(buf); + UA_ByteString_clear(buf); return UA_STATUSCODE_BADCONNECTIONCLOSED; } @@ -66796,6 +75449,10 @@ connection_write(UA_Connection *connection, UA_ByteString *buf) { int flags = 0; flags |= MSG_NOSIGNAL; + struct pollfd poll_fd[1]; + poll_fd[0].fd = connection->sockfd; + poll_fd[0].events = UA_POLLOUT; + /* Send the full buffer. This may require several calls to send */ size_t nWritten = 0; do { @@ -66805,17 +75462,24 @@ connection_write(UA_Connection *connection, UA_ByteString *buf) { n = UA_send(connection->sockfd, (const char*)buf->data + nWritten, bytes_to_send, flags); - if(n < 0 && UA_ERRNO != UA_INTERRUPTED && UA_ERRNO != UA_AGAIN) { - connection->close(connection); - UA_ByteString_deleteMembers(buf); - return UA_STATUSCODE_BADCONNECTIONCLOSED; + if(n<0) { + if(UA_ERRNO != UA_INTERRUPTED && UA_ERRNO != UA_AGAIN) { + connection->close(connection); + UA_ByteString_clear(buf); + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + int poll_ret; + do { + poll_ret = UA_poll (poll_fd, 1, 1000); + } while (poll_ret == 0 || (poll_ret < 0 && UA_ERRNO == UA_INTERRUPTED)); } } while(n < 0); + nWritten += (size_t)n; } while(nWritten < buf->length); /* Free the buffer */ - UA_ByteString_deleteMembers(buf); + UA_ByteString_clear(buf); return UA_STATUSCODE_GOOD; } @@ -66840,7 +75504,7 @@ connection_recv(UA_Connection *connection, UA_ByteString *response, if(resultsize == -1) { /* The call to select was interrupted. Act as if it timed out. */ - if(UA_ERRNO == EINTR) + if(UA_ERRNO == UA_INTERRUPTED) return UA_STATUSCODE_GOODNONCRITICALTIMEOUT; /* The error cannot be recovered. Close the connection. */ @@ -66867,7 +75531,7 @@ connection_recv(UA_Connection *connection, UA_ByteString *response, /* The remote side closed the connection */ if(ret == 0) { if(internallyAllocated) - UA_ByteString_deleteMembers(response); + UA_ByteString_clear(response); connection->close(connection); return UA_STATUSCODE_BADCONNECTIONCLOSED; } @@ -66875,7 +75539,7 @@ connection_recv(UA_Connection *connection, UA_ByteString *response, /* Error case */ if(ret < 0) { if(internallyAllocated) - UA_ByteString_deleteMembers(response); + UA_ByteString_clear(response); if(UA_ERRNO == UA_INTERRUPTED || (timeout > 0) ? false : (UA_ERRNO == UA_EAGAIN || UA_ERRNO == UA_WOULDBLOCK)) return UA_STATUSCODE_GOOD; /* statuscode_good but no data -> retry */ @@ -67005,6 +75669,8 @@ ServerNetworkLayerTCP_add(UA_ServerNetworkLayer *nl, ServerNetworkLayerTCP *laye c->state = UA_CONNECTIONSTATE_OPENING; c->openingDate = UA_DateTime_nowMonotonic(); + layer->connectionsSize++; + /* Add to the linked list */ LIST_INSERT_HEAD(&layer->connections, e, pointers); if(nl->statistics) { @@ -67020,8 +75686,9 @@ addServerSocket(ServerNetworkLayerTCP *layer, struct addrinfo *ai) { UA_SOCKET newsock = UA_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if(newsock == UA_INVALID_SOCKET) { - UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, - "Error opening the server socket"); + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Error opening the server socket: %s", errno_str)); return UA_STATUSCODE_BADCOMMUNICATIONERROR; } @@ -67058,7 +75725,36 @@ addServerSocket(ServerNetworkLayerTCP *layer, struct addrinfo *ai) { } /* Bind socket to address */ - if(UA_bind(newsock, ai->ai_addr, (socklen_t)ai->ai_addrlen) < 0) { + int ret = UA_bind(newsock, ai->ai_addr, (socklen_t)ai->ai_addrlen); + if(ret < 0) { + /* If bind to specific address failed, try to bind *-socket */ + if(ai->ai_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + if(sin->sin_addr.s_addr != htonl(INADDR_ANY)) { + sin->sin_addr.s_addr = 0; + ret = 0; + } + } +#if UA_IPV6 + else if(ai->ai_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; + if(!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); + sin6->sin6_scope_id = 0; + ret = 0; + } + } +#endif // UA_IPV6 + if(ret == 0) { + ret = UA_bind(newsock, ai->ai_addr, (socklen_t)ai->ai_addrlen); + if(ret == 0) { + /* The second bind fixed the issue, inform the user. */ + UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, + "Server socket bound to unspecified address"); + } + } + } + if(ret < 0) { UA_LOG_SOCKET_ERRNO_WRAP( UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error binding a server socket: %s", errno_str)); @@ -67090,22 +75786,43 @@ addServerSocket(ServerNetworkLayerTCP *layer, struct addrinfo *ai) { } static UA_StatusCode -ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, const UA_String *customHostname) { - UA_initialize_architecture_network(); +ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, const UA_Logger *logger, + const UA_String *customHostname) { + UA_initialize_architecture_network(); ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle; + layer->logger = logger; /* Get addrinfo of the server and create server sockets */ + char hostname[512]; + if(customHostname->length) { + if(customHostname->length >= sizeof(hostname)) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(hostname, customHostname->data, customHostname->length); + hostname[customHostname->length] = '\0'; + } char portno[6]; UA_snprintf(portno, 6, "%d", layer->port); struct addrinfo hints, *res; memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; +#if UA_IPV6 + hints.ai_family = AF_UNSPEC; /* allow IPv4 and IPv6 */ +#else + hints.ai_family = AF_INET; /* enforce IPv4 only */ +#endif hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; +#ifdef AI_ADDRCONFIG + hints.ai_flags |= AI_ADDRCONFIG; +#endif hints.ai_protocol = IPPROTO_TCP; - if(UA_getaddrinfo(NULL, portno, &hints, &res) != 0) + int retcode = UA_getaddrinfo(customHostname->length ? hostname : NULL, + portno, &hints, &res); + if(retcode != 0) { + UA_LOG_SOCKET_ERRNO_GAI_WRAP(UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "getaddrinfo lookup of %s failed with error %d - %s", hostname, retcode, errno_str)); return UA_STATUSCODE_BADINTERNALERROR; + } /* There might be serveral addrinfos (for different network cards, * IPv4/IPv6). Add a server socket for all of them. */ @@ -67113,12 +75830,13 @@ ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, const UA_String *customHo for(layer->serverSocketsSize = 0; layer->serverSocketsSize < FD_SETSIZE && ai != NULL; ai = ai->ai_next) { - UA_StatusCode statusCode = addServerSocket(layer, ai); - if(statusCode != UA_STATUSCODE_GOOD) - return statusCode; - + addServerSocket(layer, ai); } UA_freeaddrinfo(res); + + if(layer->serverSocketsSize == 0) { + return UA_STATUSCODE_BADCOMMUNICATIONERROR; + } /* Get the discovery url from the hostname */ UA_String du = UA_STRING_NULL; @@ -67197,7 +75915,7 @@ ServerNetworkLayerTCP_listen(UA_ServerNetworkLayer *nl, UA_Server *server, struct sockaddr_storage remote; socklen_t remote_size = sizeof(remote); - UA_SOCKET newsockfd = UA_accept((UA_SOCKET)layer->serverSockets[i], + UA_SOCKET newsockfd = UA_accept(layer->serverSockets[i], (struct sockaddr*)&remote, &remote_size); if(newsockfd == UA_INVALID_SOCKET) continue; @@ -67225,7 +75943,7 @@ ServerNetworkLayerTCP_listen(UA_ServerNetworkLayer *nl, UA_Server *server, UA_close(e->connection.sockfd); UA_Server_removeConnection(server, &e->connection); if(nl->statistics) { - nl->statistics->connectionTimeoutCount--; + nl->statistics->connectionTimeoutCount++; nl->statistics->currentConnectionCount--; } continue; @@ -67290,9 +76008,9 @@ ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Server *server) { /* run only when the server is stopped */ static void -ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) { +ServerNetworkLayerTCP_clear(UA_ServerNetworkLayer *nl) { ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle; - UA_String_deleteMembers(&nl->discoveryUrl); + UA_String_clear(&nl->discoveryUrl); /* Hard-close and remove remaining connections. The server is no longer * running. So this is safe. */ @@ -67313,10 +76031,10 @@ ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) { UA_ServerNetworkLayer UA_ServerNetworkLayerTCP(UA_ConnectionConfig config, UA_UInt16 port, - UA_UInt16 maxConnections, UA_Logger *logger) { + UA_UInt16 maxConnections) { UA_ServerNetworkLayer nl; memset(&nl, 0, sizeof(UA_ServerNetworkLayer)); - nl.clear = ServerNetworkLayerTCP_deleteMembers; + nl.clear = ServerNetworkLayerTCP_clear; nl.localConnectionConfig = config; nl.start = ServerNetworkLayerTCP_start; nl.listen = ServerNetworkLayerTCP_listen; @@ -67329,7 +76047,6 @@ UA_ServerNetworkLayerTCP(UA_ConnectionConfig config, UA_UInt16 port, return nl; nl.handle = layer; - layer->logger = logger; layer->port = port; layer->maxConnections = maxConnections; @@ -67363,7 +76080,7 @@ static void ClientNetworkLayerTCP_free(UA_Connection *connection) { if(!connection->handle) return; - + TCPClientConnection *tcpConnection = (TCPClientConnection *)connection->handle; if(tcpConnection->server) UA_freeaddrinfo(tcpConnection->server); @@ -67373,158 +76090,186 @@ ClientNetworkLayerTCP_free(UA_Connection *connection) { } UA_StatusCode -UA_ClientConnectionTCP_poll(UA_Client *client, void *data, UA_UInt32 timeout) { - UA_Connection *connection = (UA_Connection*) data; +UA_ClientConnectionTCP_poll(UA_Connection *connection, UA_UInt32 timeout, + const UA_Logger *logger) { if(connection->state == UA_CONNECTIONSTATE_CLOSED) return UA_STATUSCODE_BADDISCONNECT; if(connection->state == UA_CONNECTIONSTATE_ESTABLISHED) return UA_STATUSCODE_GOOD; - TCPClientConnection *tcpConnection = (TCPClientConnection*) connection->handle; - UA_SOCKET clientsockfd = connection->sockfd; - UA_ClientConfig *config = UA_Client_getConfig(client); - /* Connection timeout? */ + TCPClientConnection *tcpConnection = (TCPClientConnection*) connection->handle; if((UA_Double) (UA_DateTime_nowMonotonic() - tcpConnection->connStart) - > tcpConnection->timeout * UA_DATETIME_MSEC ) { + > (UA_Double) tcpConnection->timeout * UA_DATETIME_MSEC ) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, "Timed out"); ClientNetworkLayerTCP_close(connection); - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK, "Timed out"); return UA_STATUSCODE_BADDISCONNECT; } - /* On linux connect may immediately return with ECONNREFUSED but we still - * want to try to connect. Thus use a loop and retry until timeout is - * reached */ + /* Get a socket and connect (only once) if not already done in a previous + * call. On win32, calling connect multiple times is not recommended on + * non-blocking sockets + * (https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect). + * On posix it is also not necessary to call connect multiple times. + * + * Identification of successfull connection is done using select (writeable/errorfd) + * and getsockopt using SO_ERROR on win32 and posix. + */ + if(connection->sockfd == UA_INVALID_SOCKET) { + connection->sockfd = UA_socket(tcpConnection->server->ai_family, + tcpConnection->server->ai_socktype, + tcpConnection->server->ai_protocol); + if(connection->sockfd == UA_INVALID_SOCKET) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Could not create client socket: %s", strerror(UA_ERRNO)); + ClientNetworkLayerTCP_close(connection); + return UA_STATUSCODE_BADDISCONNECT; + } - /* Get a socket */ - if(clientsockfd <= 0) { - clientsockfd = UA_socket(tcpConnection->server->ai_family, - tcpConnection->server->ai_socktype, - tcpConnection->server->ai_protocol); - connection->sockfd = (UA_Int32)clientsockfd; /* cast for win32 */ - } + /* Non blocking connect to be able to timeout */ + if(UA_socket_set_nonblocking(connection->sockfd) != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Could not set the client socket to nonblocking"); + ClientNetworkLayerTCP_close(connection); + return UA_STATUSCODE_BADDISCONNECT; + } - if(clientsockfd == UA_INVALID_SOCKET) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK, - "Could not create client socket: %s", strerror(UA_ERRNO)); - ClientNetworkLayerTCP_close(connection); - return UA_STATUSCODE_BADDISCONNECT; - } + /* Don't have the socket create interrupt signals */ +#ifdef SO_NOSIGPIPE + int val = 1; + int sso_result = setsockopt(connection->sockfd, SOL_SOCKET, SO_NOSIGPIPE, + (void *)&val, sizeof(val)); + if(sso_result < 0) + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, "Couldn't set SO_NOSIGPIPE"); +#endif + int error = UA_connect(connection->sockfd, tcpConnection->server->ai_addr, + tcpConnection->server->ai_addrlen); - /* Non blocking connect to be able to timeout */ - if(UA_socket_set_nonblocking(clientsockfd) != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK, - "Could not set the client socket to nonblocking"); - ClientNetworkLayerTCP_close(connection); - return UA_STATUSCODE_BADDISCONNECT; + /* Connection successful */ + if(error == 0) { + connection->state = UA_CONNECTIONSTATE_ESTABLISHED; + return UA_STATUSCODE_GOOD; + } + + /* The connection failed */ + if((UA_ERRNO != UA_ERR_CONNECTION_PROGRESS)) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Connection to %.*s failed with error: %s", + (int)tcpConnection->endpointUrl.length, + tcpConnection->endpointUrl.data, strerror(UA_ERRNO)); + ClientNetworkLayerTCP_close(connection); + return UA_STATUSCODE_BADDISCONNECT; + } } - /* Non blocking connect */ - int error = UA_connect(clientsockfd, tcpConnection->server->ai_addr, - tcpConnection->server->ai_addrlen); + /* Use select to wait until connected. Return with a half-opened connection + * after a timeout. */ + UA_UInt32 timeout_usec = timeout * 1000; - if((error == -1) && (UA_ERRNO != UA_ERR_CONNECTION_PROGRESS)) { - ClientNetworkLayerTCP_close(connection); - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK, +#ifdef _OS9000 + /* OS-9 cannot use select for checking write sockets. Therefore, we need to + * use connect until success or failed */ + int resultsize = 0; + do { + u_int32 time = 0x80000001; + signal_code sig; + + timeout_usec -= 1000000/256; // Sleep 1/256 second + if(timeout_usec < 0) + break; + + _os_sleep(&time, &sig); + error = connect(connection->sockfd, tcpConnection->server->ai_addr, + tcpConnection->server->ai_addrlen); + if((error == -1 && UA_ERRNO == EISCONN) || (error == 0)) + resultsize = 1; + if(error == -1 && UA_ERRNO != EALREADY && UA_ERRNO != EINPROGRESS) + break; + } while(resultsize == 0); +#else + /* Wait in a select-call until the connection fully opens or the timeout + * happens */ + + /* On windows select both writing and error fdset */ + fd_set writing_fdset; + FD_ZERO(&writing_fdset); + UA_fd_set(connection->sockfd, &writing_fdset); + fd_set error_fdset; + FD_ZERO(&error_fdset); +#ifdef _WIN32 + UA_fd_set(connection->sockfd, &error_fdset); +#endif + struct timeval tmptv = {(long int)(timeout_usec / 1000000), + (int)(timeout_usec % 1000000)}; + + int ret = UA_select((UA_Int32)(connection->sockfd + 1), NULL, &writing_fdset, + &error_fdset, &tmptv); + + // When select fails abort connection + if(ret == -1) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, "Connection to %.*s failed with error: %s", (int)tcpConnection->endpointUrl.length, tcpConnection->endpointUrl.data, strerror(UA_ERRNO)); + ClientNetworkLayerTCP_close(connection); return UA_STATUSCODE_BADDISCONNECT; + } else if (timeout && ret == 0) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Connection to %.*s timed out", + (int)tcpConnection->endpointUrl.length, + tcpConnection->endpointUrl.data); + ClientNetworkLayerTCP_close(connection); + return UA_STATUSCODE_BADTIMEOUT; } - /* Use select to wait and check if connected */ - if(error == -1 && (UA_ERRNO == UA_ERR_CONNECTION_PROGRESS)) { - /* connection in progress. Wait until connected using select */ - UA_UInt32 timeout_usec = timeout * 1000; - -#ifdef _OS9000 - /* OS-9 can't use select for checking write sockets. - * Therefore, we need to use connect until success or failed */ - int resultsize = 0; - do { - u_int32 time = 0x80000001; - signal_code sig; - - timeout_usec -= 1000000/256; // Sleep 1/256 second - if(timeout_usec < 0) - break; + int resultsize = UA_fd_isset(connection->sockfd, &writing_fdset); +#endif - _os_sleep(&time,&sig); - error = connect(clientsockfd, tcpConnection->server->ai_addr, - tcpConnection->server->ai_addrlen); - if((error == -1 && UA_ERRNO == EISCONN) || (error == 0)) - resultsize = 1; - if(error == -1 && UA_ERRNO != EALREADY && UA_ERRNO != EINPROGRESS) - break; - } while(resultsize == 0); + /* Any errors on the socket reported? */ + OPTVAL_TYPE so_error = 0; + socklen_t len = sizeof(so_error); + ret = UA_getsockopt(connection->sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len); + if(ret != 0 || so_error != 0) { + // UA_LOG_SOCKET_ERRNO_GAI_WRAP because of so_error +#ifndef _WIN32 + char *errno_str = strerror(ret == 0 ? so_error : UA_ERRNO); #else - fd_set fdset; - FD_ZERO(&fdset); - UA_fd_set(clientsockfd, &fdset); - struct timeval tmptv = { (long int) (timeout_usec / 1000000), - (int) (timeout_usec % 1000000) }; - int resultsize = UA_select((UA_Int32) (clientsockfd + 1), NULL, &fdset, NULL, &tmptv); + char *errno_str = NULL; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, ret == 0 ? so_error : WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&errno_str, 0, + NULL); #endif - if(resultsize == 1) { - /* Windows does not have any getsockopt equivalent and it is not needed there */ + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Connection to %.*s failed with error: %s", + (int)tcpConnection->endpointUrl.length, + tcpConnection->endpointUrl.data, errno_str); #ifdef _WIN32 - connection->sockfd = clientsockfd; - connection->state = UA_CONNECTIONSTATE_ESTABLISHED; - return UA_STATUSCODE_GOOD; -#else - OPTVAL_TYPE so_error; - socklen_t len = sizeof so_error; - int ret = UA_getsockopt(clientsockfd, SOL_SOCKET, SO_ERROR, &so_error, &len); - - if(ret == 0 && so_error == 0) { - /* Connected */ - connection->state = UA_CONNECTIONSTATE_ESTABLISHED; - return UA_STATUSCODE_GOOD; - } else { - if(so_error != ECONNREFUSED) { - /* General error */ - ClientNetworkLayerTCP_close(connection); - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK, - "Connection to %.*s failed with error: %s", - (int)tcpConnection->endpointUrl.length, - tcpConnection->endpointUrl.data, - strerror(ret == 0 ? so_error : UA_ERRNO)); - return UA_STATUSCODE_BADDISCONNECT; - } - - /* On connection refused we should still try to connect. - * Connection refused happens on localhost or local ip without - * timeout. Wait until we try a again. Do not make this too - * small, otherwise the timeout is somehow wrong */ - } + LocalFree(errno_str); #endif - } - } else { - connection->state = UA_CONNECTIONSTATE_ESTABLISHED; - return UA_STATUSCODE_GOOD; + ClientNetworkLayerTCP_close(connection); + return UA_STATUSCODE_BADDISCONNECT; } -#ifdef SO_NOSIGPIPE - int val = 1; - int sso_result = setsockopt(connection->sockfd, SOL_SOCKET, - SO_NOSIGPIPE, (void*)&val, sizeof(val)); - if(sso_result < 0) - UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK, - "Couldn't set SO_NOSIGPIPE"); -#endif + /* The connection is fully opened. Otherwise, select has timed out. But we + * can retry. */ + if(resultsize > 0) + connection->state = UA_CONNECTIONSTATE_ESTABLISHED; return UA_STATUSCODE_GOOD; } UA_Connection UA_ClientConnectionTCP_init(UA_ConnectionConfig config, const UA_String endpointUrl, - UA_UInt32 timeout, UA_Logger *logger) { + UA_UInt32 timeout, const UA_Logger *logger) { UA_initialize_architecture_network(); UA_Connection connection; memset(&connection, 0, sizeof(UA_Connection)); connection.state = UA_CONNECTIONSTATE_OPENING; + connection.sockfd = UA_INVALID_SOCKET; connection.send = connection_write; connection.recv = connection_recv; connection.close = ClientNetworkLayerTCP_close; @@ -67535,6 +76280,10 @@ UA_ClientConnectionTCP_init(UA_ConnectionConfig config, const UA_String endpoint TCPClientConnection *tcpClientConnection = (TCPClientConnection*) UA_malloc(sizeof(TCPClientConnection)); + if(!tcpClientConnection) { + connection.state = UA_CONNECTIONSTATE_CLOSED; + return connection; + } memset(tcpClientConnection, 0, sizeof(TCPClientConnection)); connection.handle = (void*) tcpClientConnection; tcpClientConnection->timeout = timeout; @@ -67569,227 +76318,15 @@ UA_ClientConnectionTCP_init(UA_ConnectionConfig config, const UA_String endpoint char portStr[6]; UA_snprintf(portStr, 6, "%d", port); int error = UA_getaddrinfo(hostname, portStr, &tcpClientConnection->hints, - &tcpClientConnection->server); + &tcpClientConnection->server); if(error != 0 || !tcpClientConnection->server) { UA_LOG_SOCKET_ERRNO_GAI_WRAP(UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "DNS lookup of %s failed with error %s", - hostname, errno_str)); + "DNS lookup of %s failed with error %d - %s", + hostname, error, errno_str)); connection.state = UA_CONNECTIONSTATE_CLOSED; return connection; } - return connection; -} - -UA_Connection -UA_ClientConnectionTCP(UA_ConnectionConfig config, const UA_String endpointUrl, - UA_UInt32 timeout, UA_Logger *logger) { - UA_initialize_architecture_network(); - - UA_Connection connection; - memset(&connection, 0, sizeof(UA_Connection)); - connection.state = UA_CONNECTIONSTATE_CLOSED; - connection.send = connection_write; - connection.recv = connection_recv; - connection.close = ClientNetworkLayerTCP_close; - connection.free = ClientNetworkLayerTCP_free; - connection.getSendBuffer = connection_getsendbuffer; - connection.releaseSendBuffer = connection_releasesendbuffer; - connection.releaseRecvBuffer = connection_releaserecvbuffer; - connection.handle = NULL; - - UA_String hostnameString = UA_STRING_NULL; - UA_String pathString = UA_STRING_NULL; - UA_UInt16 port = 0; - char hostname[512]; - - UA_StatusCode parse_retval = - UA_parseEndpointUrl(&endpointUrl, &hostnameString, &port, &pathString); - if(parse_retval != UA_STATUSCODE_GOOD || hostnameString.length > 511) { - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Server url is invalid: %.*s", - (int)endpointUrl.length, endpointUrl.data); - return connection; - } - memcpy(hostname, hostnameString.data, hostnameString.length); - hostname[hostnameString.length] = 0; - - if(port == 0) { - port = 4840; - UA_LOG_INFO(logger, UA_LOGCATEGORY_NETWORK, - "No port defined, using default port %" PRIu16, port); - } - - struct addrinfo hints, *server; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - char portStr[6]; - UA_snprintf(portStr, 6, "%d", port); - int error = UA_getaddrinfo(hostname, portStr, &hints, &server); - if(error != 0 || !server) { - UA_LOG_SOCKET_ERRNO_GAI_WRAP(UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "DNS lookup of %s failed with error %s", hostname, errno_str)); - return connection; - } - - UA_Boolean connected = false; - UA_DateTime dtTimeout = timeout * UA_DATETIME_MSEC; - UA_DateTime connStart = UA_DateTime_nowMonotonic(); - UA_SOCKET clientsockfd; - - /* On linux connect may immediately return with ECONNREFUSED but we still - * want to try to connect. So use a loop and retry until timeout is - * reached. */ - do { - /* Get a socket */ - clientsockfd = UA_socket(server->ai_family, - server->ai_socktype, - server->ai_protocol); - if(clientsockfd == UA_INVALID_SOCKET) { - UA_LOG_SOCKET_ERRNO_WRAP(UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Could not create client socket: %s", errno_str)); - UA_freeaddrinfo(server); - return connection; - } - - connection.state = UA_CONNECTIONSTATE_OPENING; - - /* Connect to the server */ - connection.sockfd = clientsockfd; - - /* Non blocking connect to be able to timeout */ - if(UA_socket_set_nonblocking(clientsockfd) != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Could not set the client socket to nonblocking"); - ClientNetworkLayerTCP_close(&connection); - UA_freeaddrinfo(server); - return connection; - } - - /* Non blocking connect */ - error = UA_connect(clientsockfd, server->ai_addr, (socklen_t)server->ai_addrlen); - - if((error == -1) && (UA_ERRNO != UA_ERR_CONNECTION_PROGRESS)) { - ClientNetworkLayerTCP_close(&connection); - UA_LOG_SOCKET_ERRNO_WRAP( - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Connection to %.*s failed with error: %s", - (int)endpointUrl.length, endpointUrl.data, errno_str)); - UA_freeaddrinfo(server); - return connection; - } - - /* Use select to wait and check if connected */ - if(error == -1 && (UA_ERRNO == UA_ERR_CONNECTION_PROGRESS)) { - /* connection in progress. Wait until connected using select */ - UA_DateTime timeSinceStart = UA_DateTime_nowMonotonic() - connStart; - if(timeSinceStart > dtTimeout) - break; - -#ifdef _OS9000 - /* OS-9 can't use select for checking write sockets. - * Therefore, we need to use connect until success or failed - */ - UA_DateTime timeout_usec = (dtTimeout - timeSinceStart) / UA_DATETIME_USEC; - int resultsize = 0; - do { - u_int32 time = 0x80000001; - signal_code sig; - - timeout_usec -= 1000000/256; // Sleep 1/256 second - if(timeout_usec < 0) - break; - - _os_sleep(&time,&sig); - error = connect(clientsockfd, server->ai_addr, server->ai_addrlen); - if((error == -1 && UA_ERRNO == EISCONN) || (error == 0)) - resultsize = 1; - if(error == -1 && UA_ERRNO != EALREADY && UA_ERRNO != EINPROGRESS) - break; - } - while(resultsize == 0); -#else - fd_set fdset; - FD_ZERO(&fdset); - UA_fd_set(clientsockfd, &fdset); - UA_DateTime timeout_usec = (dtTimeout - timeSinceStart) / UA_DATETIME_USEC; - struct timeval tmptv = {(long int) (timeout_usec / 1000000), - (int) (timeout_usec % 1000000)}; - - int resultsize = UA_select((UA_Int32)(clientsockfd + 1), NULL, &fdset, NULL, &tmptv); -#endif - - if(resultsize == 1) { -#ifdef _WIN32 - /* Windows does not have any getsockopt equivalent and it is not - * needed there */ - connected = true; - break; -#else - OPTVAL_TYPE so_error; - socklen_t len = sizeof so_error; - - int ret = UA_getsockopt(clientsockfd, SOL_SOCKET, SO_ERROR, &so_error, &len); - - if(ret != 0 || so_error != 0) { - /* on connection refused we should still try to connect */ - /* connection refused happens on localhost or local ip without timeout */ - if(so_error != ECONNREFUSED) { - ClientNetworkLayerTCP_close(&connection); - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Connection to %.*s failed with error: %s", - (int)endpointUrl.length, endpointUrl.data, - strerror(ret == 0 ? so_error : UA_ERRNO)); - UA_freeaddrinfo(server); - return connection; - } - /* wait until we try a again. Do not make this too small, otherwise the - * timeout is somehow wrong */ - UA_sleep_ms(100); - } else { - connected = true; - break; - } -#endif - } - } else { - connected = true; - break; - } - ClientNetworkLayerTCP_close(&connection); - - } while ((UA_DateTime_nowMonotonic() - connStart) < dtTimeout); - - UA_freeaddrinfo(server); - - if(!connected) { - /* connection timeout */ - if(connection.state != UA_CONNECTIONSTATE_CLOSED) - ClientNetworkLayerTCP_close(&connection); - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Trying to connect to %.*s timed out", - (int)endpointUrl.length, endpointUrl.data); - return connection; - } - - - /* We are connected. Reset socket to blocking */ - if(UA_socket_set_blocking(clientsockfd) != UA_STATUSCODE_GOOD) { - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Could not set the client socket to blocking"); - ClientNetworkLayerTCP_close(&connection); - return connection; - } - -#ifdef SO_NOSIGPIPE - int val = 1; - int sso_result = UA_setsockopt(connection.sockfd, SOL_SOCKET, - SO_NOSIGPIPE, (void*)&val, sizeof(val)); - if(sso_result < 0) - UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, - "Couldn't set SO_NOSIGPIPE"); -#endif + /* Return connection with state UA_CONNECTIONSTATE_OPENING */ return connection; } |