diff options
Diffstat (limited to 'src/3rdparty/open62541/open62541.c')
-rw-r--r-- | src/3rdparty/open62541/open62541.c | 43978 |
1 files changed, 43978 insertions, 0 deletions
diff --git a/src/3rdparty/open62541/open62541.c b/src/3rdparty/open62541/open62541.c new file mode 100644 index 0000000..217137a --- /dev/null +++ b/src/3rdparty/open62541/open62541.c @@ -0,0 +1,43978 @@ +/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES + * visit http://open62541.org/ for information about this software + * Git-Revision: v0.3.0 + */ + +/* + * Copyright (C) 2014-2018 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 + * License v2.0 as stated in the LICENSE file provided with open62541. + * + * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. + */ + +#ifndef UA_DYNAMIC_LINKING_EXPORT +# define UA_DYNAMIC_LINKING_EXPORT +# define MDNSD_DYNAMIC_LINKING +#endif + +/* Enable POSIX features */ +#if !defined(_XOPEN_SOURCE) && !defined(_WRS_KERNEL) +# define _XOPEN_SOURCE 600 +#endif +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#endif +/* On older systems we need to define _BSD_SOURCE. + * _DEFAULT_SOURCE is an alias for that. */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif + +/* Disable security warnings for BSD sockets on MSVC */ +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include "open62541.h" + +/*********************************** amalgamated original file "/home/jvoe/open62541/deps/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 $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +/* Fix redefinition of SLIST_ENTRY on mingw winnt.h */ +# ifdef SLIST_ENTRY +# undef SLIST_ENTRY +# endif + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +/* + * XOR Simple queue definitions. + */ +#define XSIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqx_first; /* first element */ \ + struct type **sqx_last; /* addr of last next element */ \ + unsigned long sqx_cookie; \ +} + +#define XSIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqx_next; /* next element */ \ +} + +/* + * XOR Simple queue access methods. + */ +#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \ + (unsigned long)(ptr))) +#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first)) +#define XSIMPLEQ_END(head) NULL +#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head)) +#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next)) + + +#define XSIMPLEQ_FOREACH(var, head, field) \ + for ((var) = XSIMPLEQ_FIRST(head); \ + (var) != XSIMPLEQ_END(head); \ + (var) = XSIMPLEQ_NEXT(head, var, field)) + +#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = XSIMPLEQ_FIRST(head); \ + (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \ + (var) = (tvar)) + +/* + * XOR Simple queue functions. + */ +#define XSIMPLEQ_INIT(head) do { \ + arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \ + (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ +} while (0) + +#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqx_next = (head)->sqx_first) == \ + XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ + (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \ +} while (0) + +#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \ + *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ +} while (0) + +#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \ + XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ + (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \ +} while (0) + +#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqx_first = XSIMPLEQ_XOR(head, \ + (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ +} while (0) + +#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \ + (elm)->field.sqx_next)->field.sqx_next) \ + == XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = \ + XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ +} while (0) + + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = CIRCLEQ_LAST(head, headname); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + + +/*********************************** amalgamated original file "/home/jvoe/open62541/deps/pcg_basic.h" ***********************************/ + +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct pcg_state_setseq_64 { + uint64_t state; /* RNG state. All values are possible. */ + uint64_t inc; /* Controls which RNG sequence (stream) is selected. Must + * *always* be odd. */ +} pcg32_random_t; + +#define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL } + +void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq); +uint32_t pcg32_random_r(pcg32_random_t* rng); + +#ifdef __cplusplus +} +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/deps/libc_time.h" ***********************************/ + + +struct mytm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + /* long __tm_gmtoff; */ + /* const char *__tm_zone; */ +}; + +int __secs_to_tm(long long t, struct mytm *tm); + + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/ua_util.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) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2015 (c) LEvertz + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD Queue Macros */ + +/* Macro-Expand for MSVC workarounds */ +#define UA_MACRO_EXPAND(x) x + +/* Integer Shortnames + * ------------------ + * These are not exposed on the public API, since many user-applications make + * the same definitions in their headers. */ + +typedef UA_Byte u8; +typedef UA_SByte i8; +typedef UA_UInt16 u16; +typedef UA_Int16 i16; +typedef UA_UInt32 u32; +typedef UA_Int32 i32; +typedef UA_UInt64 u64; +typedef UA_Int64 i64; +typedef UA_StatusCode status; + +/* Atomic Operations + * ----------------- + * Atomic operations that synchronize across processor cores (for + * multithreading). Only the inline-functions defined next are used. Replace + * with architecture-specific operations if necessary. */ +#ifndef UA_ENABLE_MULTITHREADING +# define UA_atomic_sync() +#else +# ifdef _MSC_VER /* Visual Studio */ +# define UA_atomic_sync() _ReadWriteBarrier() +# else /* GCC/Clang */ +# define UA_atomic_sync() __sync_synchronize() +# endif +#endif + +static UA_INLINE void * +UA_atomic_xchg(void * volatile * addr, void *newptr) { +#ifndef UA_ENABLE_MULTITHREADING + void *old = *addr; + *addr = newptr; + return old; +#else +# ifdef _MSC_VER /* Visual Studio */ + return _InterlockedExchangePointer(addr, newptr); +# else /* GCC/Clang */ + return __sync_lock_test_and_set(addr, newptr); +# endif +#endif +} + +static UA_INLINE void * +UA_atomic_cmpxchg(void * volatile * addr, void *expected, void *newptr) { +#ifndef UA_ENABLE_MULTITHREADING + void *old = *addr; + if(old == expected) { + *addr = newptr; + } + return old; +#else +# ifdef _MSC_VER /* Visual Studio */ + return _InterlockedCompareExchangePointer(addr, expected, newptr); +# else /* GCC/Clang */ + return __sync_val_compare_and_swap(addr, expected, newptr); +# endif +#endif +} + +static UA_INLINE uint32_t +UA_atomic_addUInt32(volatile uint32_t *addr, uint32_t increase) { +#ifndef UA_ENABLE_MULTITHREADING + *addr += increase; + return *addr; +#else +# ifdef _MSC_VER /* Visual Studio */ + return _InterlockedExchangeAdd(addr, increase) + increase; +# else /* GCC/Clang */ + return __sync_add_and_fetch(addr, increase); +# endif +#endif +} + +static UA_INLINE size_t +UA_atomic_addSize(volatile size_t *addr, size_t increase) { +#ifndef UA_ENABLE_MULTITHREADING + *addr += increase; + return *addr; +#else +# ifdef _MSC_VER /* Visual Studio */ + return _InterlockedExchangeAdd(addr, increase) + increase; +# else /* GCC/Clang */ + return __sync_add_and_fetch(addr, increase); +# endif +#endif +} + +static UA_INLINE uint32_t +UA_atomic_subUInt32(volatile uint32_t *addr, uint32_t decrease) { +#ifndef UA_ENABLE_MULTITHREADING + *addr -= decrease; + return *addr; +#else +# ifdef _MSC_VER /* Visual Studio */ + return _InterlockedExchangeSub(addr, decrease) - decrease; +# else /* GCC/Clang */ + return __sync_sub_and_fetch(addr, decrease); +# endif +#endif +} + +static UA_INLINE size_t +UA_atomic_subSize(volatile size_t *addr, size_t decrease) { +#ifndef UA_ENABLE_MULTITHREADING + *addr -= decrease; + return *addr; +#else +# ifdef _MSC_VER /* Visual Studio */ + return _InterlockedExchangeSub(addr, decrease) - decrease; +# else /* GCC/Clang */ + return __sync_sub_and_fetch(addr, decrease); +# endif +#endif +} + +/* Utility Functions + * ----------------- */ + +/* Convert given byte string to a positive number. Returns the number of valid + * digits. Stops if a non-digit char is found and returns the number of digits + * up to that point. */ +size_t UA_readNumber(u8 *buf, size_t buflen, u32 *number); + +#define UA_MIN(A,B) (A > B ? B : A) +#define UA_MAX(A,B) (A > B ? A : B) + +#ifdef UA_DEBUG_DUMP_PKGS +void UA_EXPORT UA_dump_hex_pkg(UA_Byte* buffer, size_t bufferLen); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/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) Julius Pfrommer, Fraunhofer IOSB + * 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 + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +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, size_t customTypesSize, + const UA_DataType *customTypes) UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +/* 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(void *p, const UA_DataType *type); + +const UA_DataType * +UA_findDataTypeByBinary(const UA_NodeId *typeId); + +#ifdef __cplusplus +} +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_types_generated_encoding_binary.h" ***********************************/ + +/* Generated from Opc.Ua.Types.bsd with script /home/jvoe/open62541/tools/generate_datatypes.py + * on host rigel by user jvoe at 2019-01-04 01:18:40 */ + + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* SemanticChangeStructureDataType */ +static UA_INLINE UA_StatusCode +UA_SemanticChangeStructureDataType_encodeBinary(const UA_SemanticChangeStructureDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SEMANTICCHANGESTRUCTUREDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SemanticChangeStructureDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SemanticChangeStructureDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SEMANTICCHANGESTRUCTUREDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* FindServersOnNetworkRequest */ +static UA_INLINE UA_StatusCode +UA_FindServersOnNetworkRequest_encodeBinary(const UA_FindServersOnNetworkRequest *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_FindServersOnNetworkRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_FindServersOnNetworkRequest *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* MdnsDiscoveryConfiguration */ +static UA_INLINE UA_StatusCode +UA_MdnsDiscoveryConfiguration_encodeBinary(const UA_MdnsDiscoveryConfiguration *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_MdnsDiscoveryConfiguration_decodeBinary(const UA_ByteString *src, size_t *offset, UA_MdnsDiscoveryConfiguration *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* ParsingResult */ +static UA_INLINE UA_StatusCode +UA_ParsingResult_encodeBinary(const UA_ParsingResult *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_PARSINGRESULT], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_ParsingResult_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ParsingResult *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_PARSINGRESULT], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* QueryDataSet */ +static UA_INLINE UA_StatusCode +UA_QueryDataSet_encodeBinary(const UA_QueryDataSet *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUERYDATASET], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_QueryDataSet_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QueryDataSet *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUERYDATASET], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* ReferenceNode */ +static UA_INLINE UA_StatusCode +UA_ReferenceNode_encodeBinary(const UA_ReferenceNode *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REFERENCENODE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_ReferenceNode_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ReferenceNode *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REFERENCENODE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* SubscriptionDiagnosticsDataType */ +static UA_INLINE UA_StatusCode +UA_SubscriptionDiagnosticsDataType_encodeBinary(const UA_SubscriptionDiagnosticsDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SubscriptionDiagnosticsDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SubscriptionDiagnosticsDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* ServerOnNetwork */ +static UA_INLINE UA_StatusCode +UA_ServerOnNetwork_encodeBinary(const UA_ServerOnNetwork *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SERVERONNETWORK], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_ServerOnNetwork_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ServerOnNetwork *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SERVERONNETWORK], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* FindServersOnNetworkResponse */ +static UA_INLINE UA_StatusCode +UA_FindServersOnNetworkResponse_encodeBinary(const UA_FindServersOnNetworkResponse *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_FindServersOnNetworkResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_FindServersOnNetworkResponse *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* ServiceCounterDataType */ +static UA_INLINE UA_StatusCode +UA_ServiceCounterDataType_encodeBinary(const UA_ServiceCounterDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_ServiceCounterDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ServiceCounterDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], 0, NULL); +} + +/* ModelChangeStructureDataType */ +static UA_INLINE UA_StatusCode +UA_ModelChangeStructureDataType_encodeBinary(const UA_ModelChangeStructureDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_MODELCHANGESTRUCTUREDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_ModelChangeStructureDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_ModelChangeStructureDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_MODELCHANGESTRUCTUREDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* IdType */ +static UA_INLINE UA_StatusCode +UA_IdType_encodeBinary(const UA_IdType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_IDTYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_IdType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_IdType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_IDTYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* QueryNextResponse */ +static UA_INLINE UA_StatusCode +UA_QueryNextResponse_encodeBinary(const UA_QueryNextResponse *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUERYNEXTRESPONSE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_QueryNextResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QueryNextResponse *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUERYNEXTRESPONSE], 0, NULL); +} + +/* DiscoveryConfiguration */ +static UA_INLINE UA_StatusCode +UA_DiscoveryConfiguration_encodeBinary(const UA_DiscoveryConfiguration *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_DISCOVERYCONFIGURATION], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_DiscoveryConfiguration_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DiscoveryConfiguration *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_DISCOVERYCONFIGURATION], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* EndpointUrlListDataType */ +static UA_INLINE UA_StatusCode +UA_EndpointUrlListDataType_encodeBinary(const UA_EndpointUrlListDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_ENDPOINTURLLISTDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_EndpointUrlListDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_EndpointUrlListDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_ENDPOINTURLLISTDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* QueryNextRequest */ +static UA_INLINE UA_StatusCode +UA_QueryNextRequest_encodeBinary(const UA_QueryNextRequest *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUERYNEXTREQUEST], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_QueryNextRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QueryNextRequest *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUERYNEXTREQUEST], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* RedundantServerDataType */ +static UA_INLINE UA_StatusCode +UA_RedundantServerDataType_encodeBinary(const UA_RedundantServerDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REDUNDANTSERVERDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_RedundantServerDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RedundantServerDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REDUNDANTSERVERDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* SessionSecurityDiagnosticsDataType */ +static UA_INLINE UA_StatusCode +UA_SessionSecurityDiagnosticsDataType_encodeBinary(const UA_SessionSecurityDiagnosticsDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SessionSecurityDiagnosticsDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SessionSecurityDiagnosticsDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* RegisterServerResponse */ +static UA_INLINE UA_StatusCode +UA_RegisterServerResponse_encodeBinary(const UA_RegisterServerResponse *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_RegisterServerResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisterServerResponse *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* QueryDataDescription */ +static UA_INLINE UA_StatusCode +UA_QueryDataDescription_encodeBinary(const UA_QueryDataDescription *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUERYDATADESCRIPTION], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_QueryDataDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QueryDataDescription *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUERYDATADESCRIPTION], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* NetworkGroupDataType */ +static UA_INLINE UA_StatusCode +UA_NetworkGroupDataType_encodeBinary(const UA_NetworkGroupDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NETWORKGROUPDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_NetworkGroupDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkGroupDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NETWORKGROUPDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* RegisterServer2Response */ +static UA_INLINE UA_StatusCode +UA_RegisterServer2Response_encodeBinary(const UA_RegisterServer2Response *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_RegisterServer2Response_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisterServer2Response *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* NodeTypeDescription */ +static UA_INLINE UA_StatusCode +UA_NodeTypeDescription_encodeBinary(const UA_NodeTypeDescription *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_NODETYPEDESCRIPTION], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_NodeTypeDescription_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NodeTypeDescription *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_NODETYPEDESCRIPTION], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* SessionDiagnosticsDataType */ +static UA_INLINE UA_StatusCode +UA_SessionDiagnosticsDataType_encodeBinary(const UA_SessionDiagnosticsDataType *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SessionDiagnosticsDataType_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SessionDiagnosticsDataType *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* RegisteredServer */ +static UA_INLINE UA_StatusCode +UA_RegisteredServer_encodeBinary(const UA_RegisteredServer *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTEREDSERVER], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_RegisteredServer_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisteredServer *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTEREDSERVER], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* RegisterServerRequest */ +static UA_INLINE UA_StatusCode +UA_RegisterServerRequest_encodeBinary(const UA_RegisterServerRequest *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_RegisterServerRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisterServerRequest *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* QueryFirstResponse */ +static UA_INLINE UA_StatusCode +UA_QueryFirstResponse_encodeBinary(const UA_QueryFirstResponse *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_QueryFirstResponse_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QueryFirstResponse *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* RegisterServer2Request */ +static UA_INLINE UA_StatusCode +UA_RegisterServer2Request_encodeBinary(const UA_RegisterServer2Request *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_RegisterServer2Request_decodeBinary(const UA_ByteString *src, size_t *offset, UA_RegisterServer2Request *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* QueryFirstRequest */ +static UA_INLINE UA_StatusCode +UA_QueryFirstRequest_encodeBinary(const UA_QueryFirstRequest *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_QueryFirstRequest_decodeBinary(const UA_ByteString *src, size_t *offset, UA_QueryFirstRequest *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST], 0, NULL); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_transport_generated.h" ***********************************/ + +/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/jvoe/open62541/tools/generate_datatypes.py + * on host rigel by user jvoe at 2019-01-04 01:18:40 */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef UA_NO_AMALGAMATION + +#else +#endif + + +/** + * Every type is assigned an index in an array containing the type descriptions. + * These descriptions are used during type handling (copying, deletion, + * binary encoding, ...). */ +#define UA_TRANSPORT_COUNT 12 +extern UA_EXPORT const UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT]; + +/** + * SecureConversationMessageAbortBody + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Secure Conversation Message Abort Body */ +typedef struct { + UA_UInt32 error; + UA_String reason; +} UA_SecureConversationMessageAbortBody; + +#define UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY 0 + +/** + * SecureConversationMessageFooter + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Secure Conversation Message Footer */ +typedef struct { + size_t paddingSize; + UA_Byte *padding; + UA_Byte signature; +} UA_SecureConversationMessageFooter; + +#define UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER 1 + +/** + * TcpHelloMessage + * ^^^^^^^^^^^^^^^ + * Hello Message */ +typedef struct { + UA_UInt32 protocolVersion; + UA_UInt32 receiveBufferSize; + UA_UInt32 sendBufferSize; + UA_UInt32 maxMessageSize; + UA_UInt32 maxChunkCount; + UA_String endpointUrl; +} UA_TcpHelloMessage; + +#define UA_TRANSPORT_TCPHELLOMESSAGE 2 + +/** + * TcpErrorMessage + * ^^^^^^^^^^^^^^^ + * Error Message */ +typedef struct { + UA_UInt32 error; + UA_String reason; +} UA_TcpErrorMessage; + +#define UA_TRANSPORT_TCPERRORMESSAGE 3 + +/** + * MessageType + * ^^^^^^^^^^^ + * Message Type and whether the message contains an intermediate chunk */ +typedef enum { + UA_MESSAGETYPE_ACK = 0x4B4341, + UA_MESSAGETYPE_HEL = 0x4C4548, + UA_MESSAGETYPE_MSG = 0x47534D, + UA_MESSAGETYPE_OPN = 0x4E504F, + UA_MESSAGETYPE_CLO = 0x4F4C43, + UA_MESSAGETYPE_ERR = 0x525245, + __UA_MESSAGETYPE_FORCE32BIT = 0x7fffffff +} UA_MessageType; +UA_STATIC_ASSERT(sizeof(UA_MessageType) == sizeof(UA_Int32), enum_must_be_32bit); + +#define UA_TRANSPORT_MESSAGETYPE 4 + +/** + * AsymmetricAlgorithmSecurityHeader + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Security Header */ +typedef struct { + UA_ByteString securityPolicyUri; + UA_ByteString senderCertificate; + UA_ByteString receiverCertificateThumbprint; +} UA_AsymmetricAlgorithmSecurityHeader; + +#define UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER 5 + +/** + * TcpAcknowledgeMessage + * ^^^^^^^^^^^^^^^^^^^^^ + * Acknowledge Message */ +typedef struct { + UA_UInt32 protocolVersion; + UA_UInt32 receiveBufferSize; + UA_UInt32 sendBufferSize; + UA_UInt32 maxMessageSize; + UA_UInt32 maxChunkCount; +} UA_TcpAcknowledgeMessage; + +#define UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE 6 + +/** + * SequenceHeader + * ^^^^^^^^^^^^^^ + * Secure Layer Sequence Header */ +typedef struct { + UA_UInt32 sequenceNumber; + UA_UInt32 requestId; +} UA_SequenceHeader; + +#define UA_TRANSPORT_SEQUENCEHEADER 7 + +/** + * TcpMessageHeader + * ^^^^^^^^^^^^^^^^ + * TCP Header */ +typedef struct { + UA_UInt32 messageTypeAndChunkType; + UA_UInt32 messageSize; +} UA_TcpMessageHeader; + +#define UA_TRANSPORT_TCPMESSAGEHEADER 8 + +/** + * ChunkType + * ^^^^^^^^^ + * Type of the chunk */ +typedef enum { + UA_CHUNKTYPE_FINAL = 0x46000000, + UA_CHUNKTYPE_INTERMEDIATE = 0x43000000, + UA_CHUNKTYPE_ABORT = 0x41000000, + __UA_CHUNKTYPE_FORCE32BIT = 0x7fffffff +} UA_ChunkType; +UA_STATIC_ASSERT(sizeof(UA_ChunkType) == sizeof(UA_Int32), enum_must_be_32bit); + +#define UA_TRANSPORT_CHUNKTYPE 9 + +/** + * SymmetricAlgorithmSecurityHeader + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Secure Layer Symmetric Algorithm Header */ +typedef struct { + UA_UInt32 tokenId; +} UA_SymmetricAlgorithmSecurityHeader; + +#define UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER 10 + +/** + * SecureConversationMessageHeader + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Secure Layer Sequence Header */ +typedef struct { + UA_TcpMessageHeader messageHeader; + UA_UInt32 secureChannelId; +} UA_SecureConversationMessageHeader; + +#define UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER 11 + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_transport_generated_handling.h" ***********************************/ + +/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/jvoe/open62541/tools/generate_datatypes.py + * on host rigel by user jvoe at 2019-01-04 01:18:40 */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +# pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + + +/* SecureConversationMessageAbortBody */ +static UA_INLINE void +UA_SecureConversationMessageAbortBody_init(UA_SecureConversationMessageAbortBody *p) { + memset(p, 0, sizeof(UA_SecureConversationMessageAbortBody)); +} + +static UA_INLINE UA_SecureConversationMessageAbortBody * +UA_SecureConversationMessageAbortBody_new(void) { + return (UA_SecureConversationMessageAbortBody*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY]); +} + +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageAbortBody_copy(const UA_SecureConversationMessageAbortBody *src, UA_SecureConversationMessageAbortBody *dst) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY]); +} + +static UA_INLINE void +UA_SecureConversationMessageAbortBody_deleteMembers(UA_SecureConversationMessageAbortBody *p) { + UA_deleteMembers(p, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY]); +} + +static UA_INLINE void +UA_SecureConversationMessageAbortBody_delete(UA_SecureConversationMessageAbortBody *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY]); +} + +/* SecureConversationMessageFooter */ +static UA_INLINE void +UA_SecureConversationMessageFooter_init(UA_SecureConversationMessageFooter *p) { + memset(p, 0, sizeof(UA_SecureConversationMessageFooter)); +} + +static UA_INLINE UA_SecureConversationMessageFooter * +UA_SecureConversationMessageFooter_new(void) { + return (UA_SecureConversationMessageFooter*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER]); +} + +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageFooter_copy(const UA_SecureConversationMessageFooter *src, UA_SecureConversationMessageFooter *dst) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER]); +} + +static UA_INLINE void +UA_SecureConversationMessageFooter_deleteMembers(UA_SecureConversationMessageFooter *p) { + UA_deleteMembers(p, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER]); +} + +static UA_INLINE void +UA_SecureConversationMessageFooter_delete(UA_SecureConversationMessageFooter *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER]); +} + +/* TcpHelloMessage */ +static UA_INLINE void +UA_TcpHelloMessage_init(UA_TcpHelloMessage *p) { + memset(p, 0, sizeof(UA_TcpHelloMessage)); +} + +static UA_INLINE UA_TcpHelloMessage * +UA_TcpHelloMessage_new(void) { + return (UA_TcpHelloMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); +} + +static UA_INLINE UA_StatusCode +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_TcpHelloMessage_deleteMembers(UA_TcpHelloMessage *p) { + UA_deleteMembers(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); +} + +static UA_INLINE void +UA_TcpHelloMessage_delete(UA_TcpHelloMessage *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); +} + +/* TcpErrorMessage */ +static UA_INLINE void +UA_TcpErrorMessage_init(UA_TcpErrorMessage *p) { + memset(p, 0, sizeof(UA_TcpErrorMessage)); +} + +static UA_INLINE UA_TcpErrorMessage * +UA_TcpErrorMessage_new(void) { + return (UA_TcpErrorMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); +} + +static UA_INLINE UA_StatusCode +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_TcpErrorMessage_deleteMembers(UA_TcpErrorMessage *p) { + UA_deleteMembers(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); +} + +static UA_INLINE void +UA_TcpErrorMessage_delete(UA_TcpErrorMessage *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); +} + +/* MessageType */ +static UA_INLINE void +UA_MessageType_init(UA_MessageType *p) { + memset(p, 0, sizeof(UA_MessageType)); +} + +static UA_INLINE UA_MessageType * +UA_MessageType_new(void) { + return (UA_MessageType*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); +} + +static UA_INLINE UA_StatusCode +UA_MessageType_copy(const UA_MessageType *src, UA_MessageType *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_MessageType_deleteMembers(UA_MessageType *p) { } + +static UA_INLINE void +UA_MessageType_delete(UA_MessageType *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); +} + +/* AsymmetricAlgorithmSecurityHeader */ +static UA_INLINE void +UA_AsymmetricAlgorithmSecurityHeader_init(UA_AsymmetricAlgorithmSecurityHeader *p) { + memset(p, 0, sizeof(UA_AsymmetricAlgorithmSecurityHeader)); +} + +static UA_INLINE UA_AsymmetricAlgorithmSecurityHeader * +UA_AsymmetricAlgorithmSecurityHeader_new(void) { + return (UA_AsymmetricAlgorithmSecurityHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +static UA_INLINE UA_StatusCode +UA_AsymmetricAlgorithmSecurityHeader_copy(const UA_AsymmetricAlgorithmSecurityHeader *src, UA_AsymmetricAlgorithmSecurityHeader *dst) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +static UA_INLINE void +UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(UA_AsymmetricAlgorithmSecurityHeader *p) { + UA_deleteMembers(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +static UA_INLINE void +UA_AsymmetricAlgorithmSecurityHeader_delete(UA_AsymmetricAlgorithmSecurityHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +/* TcpAcknowledgeMessage */ +static UA_INLINE void +UA_TcpAcknowledgeMessage_init(UA_TcpAcknowledgeMessage *p) { + memset(p, 0, sizeof(UA_TcpAcknowledgeMessage)); +} + +static UA_INLINE UA_TcpAcknowledgeMessage * +UA_TcpAcknowledgeMessage_new(void) { + return (UA_TcpAcknowledgeMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); +} + +static UA_INLINE UA_StatusCode +UA_TcpAcknowledgeMessage_copy(const UA_TcpAcknowledgeMessage *src, UA_TcpAcknowledgeMessage *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_TcpAcknowledgeMessage_deleteMembers(UA_TcpAcknowledgeMessage *p) { } + +static UA_INLINE void +UA_TcpAcknowledgeMessage_delete(UA_TcpAcknowledgeMessage *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); +} + +/* SequenceHeader */ +static UA_INLINE void +UA_SequenceHeader_init(UA_SequenceHeader *p) { + memset(p, 0, sizeof(UA_SequenceHeader)); +} + +static UA_INLINE UA_SequenceHeader * +UA_SequenceHeader_new(void) { + return (UA_SequenceHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); +} + +static UA_INLINE UA_StatusCode +UA_SequenceHeader_copy(const UA_SequenceHeader *src, UA_SequenceHeader *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_SequenceHeader_deleteMembers(UA_SequenceHeader *p) { } + +static UA_INLINE void +UA_SequenceHeader_delete(UA_SequenceHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); +} + +/* TcpMessageHeader */ +static UA_INLINE void +UA_TcpMessageHeader_init(UA_TcpMessageHeader *p) { + memset(p, 0, sizeof(UA_TcpMessageHeader)); +} + +static UA_INLINE UA_TcpMessageHeader * +UA_TcpMessageHeader_new(void) { + return (UA_TcpMessageHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); +} + +static UA_INLINE UA_StatusCode +UA_TcpMessageHeader_copy(const UA_TcpMessageHeader *src, UA_TcpMessageHeader *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_TcpMessageHeader_deleteMembers(UA_TcpMessageHeader *p) { } + +static UA_INLINE void +UA_TcpMessageHeader_delete(UA_TcpMessageHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); +} + +/* ChunkType */ +static UA_INLINE void +UA_ChunkType_init(UA_ChunkType *p) { + memset(p, 0, sizeof(UA_ChunkType)); +} + +static UA_INLINE UA_ChunkType * +UA_ChunkType_new(void) { + return (UA_ChunkType*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); +} + +static UA_INLINE UA_StatusCode +UA_ChunkType_copy(const UA_ChunkType *src, UA_ChunkType *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_ChunkType_deleteMembers(UA_ChunkType *p) { } + +static UA_INLINE void +UA_ChunkType_delete(UA_ChunkType *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); +} + +/* SymmetricAlgorithmSecurityHeader */ +static UA_INLINE void +UA_SymmetricAlgorithmSecurityHeader_init(UA_SymmetricAlgorithmSecurityHeader *p) { + memset(p, 0, sizeof(UA_SymmetricAlgorithmSecurityHeader)); +} + +static UA_INLINE UA_SymmetricAlgorithmSecurityHeader * +UA_SymmetricAlgorithmSecurityHeader_new(void) { + return (UA_SymmetricAlgorithmSecurityHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER]); +} + +static UA_INLINE UA_StatusCode +UA_SymmetricAlgorithmSecurityHeader_copy(const UA_SymmetricAlgorithmSecurityHeader *src, UA_SymmetricAlgorithmSecurityHeader *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_SymmetricAlgorithmSecurityHeader_deleteMembers(UA_SymmetricAlgorithmSecurityHeader *p) { } + +static UA_INLINE void +UA_SymmetricAlgorithmSecurityHeader_delete(UA_SymmetricAlgorithmSecurityHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER]); +} + +/* SecureConversationMessageHeader */ +static UA_INLINE void +UA_SecureConversationMessageHeader_init(UA_SecureConversationMessageHeader *p) { + memset(p, 0, sizeof(UA_SecureConversationMessageHeader)); +} + +static UA_INLINE UA_SecureConversationMessageHeader * +UA_SecureConversationMessageHeader_new(void) { + return (UA_SecureConversationMessageHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER]); +} + +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageHeader_copy(const UA_SecureConversationMessageHeader *src, UA_SecureConversationMessageHeader *dst) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_INLINE void +UA_SecureConversationMessageHeader_deleteMembers(UA_SecureConversationMessageHeader *p) { } + +static UA_INLINE void +UA_SecureConversationMessageHeader_delete(UA_SecureConversationMessageHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER]); +} + +#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +# pragma GCC diagnostic pop +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_transport_generated_encoding_binary.h" ***********************************/ + +/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/jvoe/open62541/tools/generate_datatypes.py + * on host rigel by user jvoe at 2019-01-04 01:18:40 */ + + +/* SecureConversationMessageAbortBody */ +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageAbortBody_encodeBinary(const UA_SecureConversationMessageAbortBody *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageAbortBody_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SecureConversationMessageAbortBody *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY], 0, NULL); +} + +/* SecureConversationMessageFooter */ +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageFooter_encodeBinary(const UA_SecureConversationMessageFooter *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageFooter_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SecureConversationMessageFooter *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* 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], 0, NULL); +} + +/* SymmetricAlgorithmSecurityHeader */ +static UA_INLINE UA_StatusCode +UA_SymmetricAlgorithmSecurityHeader_encodeBinary(const UA_SymmetricAlgorithmSecurityHeader *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SymmetricAlgorithmSecurityHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SymmetricAlgorithmSecurityHeader *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER], 0, NULL); +} + +/* SecureConversationMessageHeader */ +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageHeader_encodeBinary(const UA_SecureConversationMessageHeader *src, UA_Byte **bufPos, const UA_Byte **bufEnd) { + return UA_encodeBinary(src, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER], bufPos, bufEnd, NULL, NULL); +} +static UA_INLINE UA_StatusCode +UA_SecureConversationMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_SecureConversationMessageHeader *dst) { + return UA_decodeBinary(src, offset, dst, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER], 0, NULL); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2016-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Florian Palm + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* The application can be the client or the server */ +typedef UA_StatusCode (*UA_Connection_processChunk)(void *application, + UA_Connection *connection, + UA_ByteString *chunk); + +/* The network layer may receive chopped up messages since TCP is a streaming + * protocol. This method calls the processChunk callback on all full chunks that + * were received. Dangling half-complete chunks are buffered in the connection + * and considered for the next received packet. + * + * If an entire chunk is received, it is forwarded directly. But the memory + * needs to be freed with the networklayer-specific mechanism. If a half message + * is received, we copy it into a local buffer. Then, the stack-specific free + * needs to be used. + * + * @param connection The connection + * @param application The client or server application + * @param processCallback The function pointer for processing each chunk + * @param packet The received packet. + * @return Returns UA_STATUSCODE_GOOD or an error code. When an error occurs, + * the ingoing message and the current buffer in the connection are + * freed. */ +UA_StatusCode +UA_Connection_processChunks(UA_Connection *connection, void *application, + UA_Connection_processChunk processCallback, + const UA_ByteString *packet); + +/* Try to receive at least one complete chunk on the connection. This blocks the + * current thread up to the given timeout. + * + * @param connection The connection + * @param application The client or server application + * @param processCallback The function pointer for processing each chunk + * @param timeout The timeout (in milliseconds) the method will block at most. + * @return Returns UA_STATUSCODE_GOOD or an error code. When an timeout occurs, + * UA_STATUSCODE_GOODNONCRITICALTIMEOUT is returned. */ +UA_StatusCode +UA_Connection_receiveChunksBlocking(UA_Connection *connection, void *application, + UA_Connection_processChunk processCallback, + UA_UInt32 timeout); + +/* When a fatal error occurs the Server shall send an Error Message to the + * Client and close the socket. When a Client encounters one of these errors, it + * shall also close the socket but does not send an Error Message. After the + * socket is closed a Client shall try to reconnect automatically using the + * mechanisms described in [...]. */ +void +UA_Connection_sendError(UA_Connection *connection, + UA_TcpErrorMessage *error); + +void UA_Connection_detachSecureChannel(UA_Connection *connection); +void UA_Connection_attachSecureChannel(UA_Connection *connection, + UA_SecureChannel *channel); + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH 12 +#define UA_SECURE_MESSAGE_HEADER_LENGTH 24 + +/* Thread-local variables to force failure modes during testing */ +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS +extern UA_StatusCode decrypt_verifySignatureFailure; +extern UA_StatusCode sendAsym_sendFailure; +extern UA_StatusCode processSym_seqNumberFailure; +#endif + +/* The Session implementation differs between client and server. Still, it is + * expected that the Session structure begins with the SessionHeader. This is + * the interface that will be used by the SecureChannel. The lifecycle of + * Sessions is independent of the underlying SecureChannel. But every Session + * can be attached to only one SecureChannel. */ +typedef struct UA_SessionHeader { + LIST_ENTRY(UA_SessionHeader) pointers; + UA_NodeId authenticationToken; + UA_SecureChannel *channel; /* The pointer back to the SecureChannel in the session. */ +} UA_SessionHeader; + +/* For chunked requests */ +struct ChunkPayload { + SIMPLEQ_ENTRY(ChunkPayload) pointers; + UA_ByteString bytes; +}; + +struct MessageEntry { + LIST_ENTRY(MessageEntry) pointers; + UA_UInt32 requestId; + SIMPLEQ_HEAD(chunkpayload_pointerlist, ChunkPayload) chunkPayload; + size_t chunkPayloadSize; +}; + +typedef enum { + UA_SECURECHANNELSTATE_FRESH, + UA_SECURECHANNELSTATE_OPEN, + UA_SECURECHANNELSTATE_CLOSED +} UA_SecureChannelState; + +struct UA_SecureChannel { + UA_SecureChannelState state; + UA_MessageSecurityMode securityMode; + UA_ChannelSecurityToken securityToken; /* the channelId is contained in the securityToken */ + /* We use three tokens because when switching tokens the client is allowed to accept + * messages with the old token for up to 25% of the lifetime after the token would have timed out. + * For messages that are sent, the new token is already used, which is contained in the securityToken + * variable. The nextSecurityToken variable holds a newly issued token, that will be automatically + * revolved into the securityToken variable. This could be done with two variables, but would require + * greater changes to the current code. This could be done in the future after the client and networking + * structure has been reworked, which would make this easier to implement. */ + UA_ChannelSecurityToken nextSecurityToken; + UA_ChannelSecurityToken previousSecurityToken; + + /* The endpoint and context of the channel */ + const UA_SecurityPolicy *securityPolicy; + void *channelContext; /* For interaction with the security policy */ + UA_Connection *connection; + + /* Asymmetric encryption info */ + UA_ByteString remoteCertificate; + UA_Byte remoteCertificateThumbprint[20]; /* The thumbprint of the remote certificate */ + + /* Symmetric encryption info */ + UA_ByteString remoteNonce; + UA_ByteString localNonce; + + UA_UInt32 receiveSequenceNumber; + UA_UInt32 sendSequenceNumber; + + LIST_HEAD(session_pointerlist, UA_SessionHeader) sessions; + LIST_HEAD(chunk_pointerlist, MessageEntry) chunks; +}; + +UA_StatusCode +UA_SecureChannel_init(UA_SecureChannel *channel, + const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate); +void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel); + +/* Generates new keys and sets them in the channel context */ +UA_StatusCode +UA_SecureChannel_generateNewKeys(UA_SecureChannel* channel); + +/* Wrapper function for generating a local nonce for the supplied channel. Uses + * the random generator of the channels security policy to allocate and generate + * a nonce with the specified length. */ +UA_StatusCode +UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel); + +UA_SessionHeader * +UA_SecureChannel_getSession(UA_SecureChannel *channel, + const UA_NodeId *authenticationToken); + +UA_StatusCode +UA_SecureChannel_revolveTokens(UA_SecureChannel *channel); + +/** + * Sending Messages + * ---------------- */ + +UA_StatusCode +UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 requestId, + const void *content, const UA_DataType *contentType); + +UA_StatusCode +UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId, + UA_MessageType messageType, void *payload, + const UA_DataType *payloadType); + +/* The MessageContext is forwarded into the encoding layer so that we can send + * chunks before continuing to encode. This lets us reuse a fixed chunk-sized + * messages buffer. */ +typedef struct { + UA_SecureChannel *channel; + UA_UInt32 requestId; + UA_UInt32 messageType; + + UA_UInt16 chunksSoFar; + size_t messageSizeSoFar; + + UA_ByteString messageBuffer; + UA_Byte *buf_pos; + const UA_Byte *buf_end; + + UA_Boolean final; +} UA_MessageContext; + +/* Start the context of a new symmetric message. */ +UA_StatusCode +UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel, + UA_UInt32 requestId, UA_MessageType messageType); + +/* Encode the content and send out full chunks. If the return code is good, then + * the ChunkInfo contains encoded content that has not been sent. If the return + * code is bad, then the ChunkInfo has been cleaned up internally. */ +UA_StatusCode +UA_MessageContext_encode(UA_MessageContext *mc, const void *content, + const UA_DataType *contentType); + +/* Sends a symmetric message already encoded in the context. The context is + * cleaned up, also in case of errors. */ +UA_StatusCode +UA_MessageContext_finish(UA_MessageContext *mc); + +/* To be used when a failure occures when a MessageContext is open. Note that + * the _encode and _finish methods will clean up internally. _abort can be run + * on a MessageContext that has already been cleaned up before. */ +void +UA_MessageContext_abort(UA_MessageContext *mc); + +/** + * Process Received Chunks + * ----------------------- */ + +typedef UA_StatusCode +(UA_ProcessMessageCallback)(void *application, UA_SecureChannel *channel, + UA_MessageType messageType, UA_UInt32 requestId, + const UA_ByteString *message); + +/* Process a single chunk. This also decrypts the chunk if required. The + * callback function is called with the complete message body if the message is + * complete. + * + * Symmetric callback is ERR, MSG, CLO only + * Asymmetric callback is OPN only + * + * @param channel the channel the chunks were received on. + * @param chunks the memory region where the chunks are stored. + * @param callback the callback function that gets called with the complete + * message body, once a final chunk is processed. + * @param application data pointer to application specific data that gets passed + * on to the callback function. */ +UA_StatusCode +UA_SecureChannel_processChunk(UA_SecureChannel *channel, UA_ByteString *chunk, + UA_ProcessMessageCallback callback, + void *application, + UA_Boolean allowPreviousToken); + +/** + * Log Helper + * ---------- + * C99 requires at least one element for the variadic argument. If the log + * statement has no variable arguments, supply an additional NULL. It will be + * ignored by printf. + * + * We have to jump through some hoops to enable the use of format strings + * without arguments since (pedantic) C99 does not allow variadic macros with + * zero arguments. So we add a dummy argument that is not printed (%.0s is + * string of length zero). */ + +#define UA_LOG_TRACE_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \ + UA_LOG_TRACE(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \ + "Connection %i | SecureChannel %i | " MSG "%.0s", \ + ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \ + (CHANNEL)->securityToken.channelId, __VA_ARGS__) + +#define UA_LOG_TRACE_CHANNEL(LOGGER, CHANNEL, ...) \ + UA_MACRO_EXPAND(UA_LOG_TRACE_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, "")) + +#define UA_LOG_DEBUG_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \ + UA_LOG_DEBUG(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \ + "Connection %i | SecureChannel %i | " MSG "%.0s", \ + ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \ + (CHANNEL)->securityToken.channelId, __VA_ARGS__) + +#define UA_LOG_DEBUG_CHANNEL(LOGGER, CHANNEL, ...) \ + UA_MACRO_EXPAND(UA_LOG_DEBUG_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, "")) + +#define UA_LOG_INFO_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \ + UA_LOG_INFO(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \ + "Connection %i | SecureChannel %i | " MSG "%.0s", \ + ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \ + (CHANNEL)->securityToken.channelId, __VA_ARGS__) + +#define UA_LOG_INFO_CHANNEL(LOGGER, CHANNEL, ...) \ + UA_MACRO_EXPAND(UA_LOG_INFO_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, "")) + +#define UA_LOG_WARNING_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \ + UA_LOG_WARNING(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \ + "Connection %i | SecureChannel %i | " MSG "%.0s", \ + ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \ + (CHANNEL)->securityToken.channelId, __VA_ARGS__) + +#define UA_LOG_WARNING_CHANNEL(LOGGER, CHANNEL, ...) \ + UA_MACRO_EXPAND(UA_LOG_WARNING_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, "")) + +#define UA_LOG_ERROR_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \ + UA_LOG_ERROR(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \ + "Connection %i | SecureChannel %i | " MSG "%.0s", \ + ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \ + (CHANNEL)->securityToken.channelId, __VA_ARGS__) + +#define UA_LOG_ERROR_CHANNEL(LOGGER, CHANNEL, ...) \ + UA_MACRO_EXPAND(UA_LOG_ERROR_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, "")) + +#define UA_LOG_FATAL_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \ + UA_LOG_FATAL(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \ + "Connection %i | SecureChannel %i | " MSG "%.0s", \ + ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \ + (CHANNEL)->securityToken.channelId, __VA_ARGS__) + +#define UA_LOG_FATAL_CHANNEL(LOGGER, CHANNEL, ...) \ + UA_MACRO_EXPAND(UA_LOG_FATAL_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, "")) + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/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 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* An (event) timer triggers callbacks with a recurring interval. Adding, + * removing and changing repeated callbacks can be done from independent + * threads. Processing the changes and dispatching callbacks must be done by a + * single "mainloop" process. + * Timer callbacks with the same recurring interval are batched into blocks in + * order to reduce linear search for re-entry to the sorted list after processing. + * Callbacks are inserted in reversed order (last callback are put first in the block) + * to allow the monitored items of a subscription (if created in a sequence with the + * same publish/sample interval) to be executed before the subscription publish the + * notifications. When callbacks are entered to the timer list after execution they + * are added in the same order as before execution. */ + +/* Forward declaration */ +struct UA_TimerCallbackEntry; +typedef struct UA_TimerCallbackEntry UA_TimerCallbackEntry; + +/* Linked-list definition */ +typedef SLIST_HEAD(UA_TimerCallbackList, UA_TimerCallbackEntry) UA_TimerCallbackList; + +typedef struct { + /* The linked list of callbacks is sorted according to the execution timestamp. */ + UA_TimerCallbackList repeatedCallbacks; + + /* Changes to the repeated callbacks in a multi-producer single-consumer queue */ + UA_TimerCallbackEntry * volatile changes_head; + UA_TimerCallbackEntry *changes_tail; + UA_TimerCallbackEntry *changes_stub; + + UA_UInt64 idCounter; +} UA_Timer; + +/* Initialize the Timer. Not thread-safe. */ +void UA_Timer_init(UA_Timer *t); + +/* Add a repated callback. Thread-safe, can be used in parallel and in parallel + * with UA_Timer_process. */ +typedef void (*UA_TimerCallback)(void *application, void *data); + +UA_StatusCode +UA_Timer_addRepeatedCallback(UA_Timer *t, UA_TimerCallback callback, void *data, + UA_UInt32 interval, 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_UInt32 interval); + +/* Remove a repated callback. Thread-safe, can be used in parallel and in + * parallel with UA_Timer_process. */ +UA_StatusCode +UA_Timer_removeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId); + +/* Process (dispatch) the repeated callbacks that have timed out. Returns the + * timestamp of the next scheduled repeated callback. Not thread-safe. + * Application is a pointer to the client / server environment for the callback. + * Dispatched is set to true when at least one callback was run / dispatched. */ +typedef void (*UA_TimerDispatchCallback)(void *application, UA_TimerCallback callback, + void *data); + +UA_DateTime +UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic, + UA_TimerDispatchCallback dispatchCallback, + void *application); + +/* Remove all repeated callbacks. Not thread-safe. */ +void UA_Timer_deleteMembers(UA_Timer *t); + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2018 (c) Julius Pfrommer, Fraunhofer IOSB + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define UA_MAXCONTINUATIONPOINTS 5 + +typedef struct ContinuationPointEntry { + LIST_ENTRY(ContinuationPointEntry) pointers; + UA_ByteString identifier; + UA_BrowseDescription browseDescription; + UA_UInt32 maxReferences; + + /* The last point in the node references? */ + size_t referenceKindIndex; + size_t targetIndex; +} ContinuationPointEntry; + +struct UA_Subscription; +typedef struct UA_Subscription UA_Subscription; + +#ifdef UA_ENABLE_SUBSCRIPTIONS +typedef struct UA_PublishResponseEntry { + SIMPLEQ_ENTRY(UA_PublishResponseEntry) listEntry; + UA_UInt32 requestId; + UA_PublishResponse response; +} UA_PublishResponseEntry; +#endif + +typedef struct { + UA_SessionHeader header; + UA_ApplicationDescription clientDescription; + UA_String sessionName; + UA_Boolean activated; + void *sessionHandle; // pointer assigned in userland-callback + UA_NodeId sessionId; + UA_UInt32 maxRequestMessageSize; + UA_UInt32 maxResponseMessageSize; + UA_Double timeout; // [ms] + UA_DateTime validTill; + UA_ByteString serverNonce; + UA_UInt16 availableContinuationPoints; + LIST_HEAD(ContinuationPointList, ContinuationPointEntry) continuationPoints; +#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 */ +#endif +} UA_Session; + +/** + * Session Lifecycle + * ----------------- */ + +void UA_Session_init(UA_Session *session); +void UA_Session_deleteMembersCleanup(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); + +/* If any activity on a session happens, the timeout is extended */ +void UA_Session_updateLifetime(UA_Session *session); + +/** + * Subscription handling + * --------------------- */ + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +void UA_Session_addSubscription(UA_Session *session, UA_Subscription *newSubscription); +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, UA_PublishResponseEntry* entry, UA_Boolean head); +UA_PublishResponseEntry* UA_Session_dequeuePublishReq(UA_Session *session); + +#endif + +/** + * Log Helper + * ---------- + * We have to jump through some hoops to enable the use of format strings + * without arguments since (pedantic) C99 does not allow variadic macros with + * zero arguments. So we add a dummy argument that is not printed (%.0s is + * string of length zero). */ + +#define UA_LOG_TRACE_SESSION_INTERNAL(LOGGER, SESSION, MSG, ...) \ + UA_LOG_TRACE(LOGGER, UA_LOGCATEGORY_SESSION, \ + "Connection %i | SecureChannel %i | Session " UA_PRINTF_GUID_FORMAT " | " MSG "%.0s", \ + ((SESSION)->header.channel ? ((SESSION)->header.channel->connection ? (SESSION)->header.channel->connection->sockfd : 0) : 0), \ + ((SESSION)->header.channel ? (SESSION)->header.channel->securityToken.channelId : 0), \ + UA_PRINTF_GUID_DATA((SESSION)->sessionId.identifier.guid), __VA_ARGS__) + +#define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_TRACE_SESSION_INTERNAL(LOGGER, SESSION, __VA_ARGS__, "")) + +#define UA_LOG_DEBUG_SESSION_INTERNAL(LOGGER, SESSION, MSG, ...) \ + UA_LOG_DEBUG(LOGGER, UA_LOGCATEGORY_SESSION, \ + "Connection %i | SecureChannel %i | Session " UA_PRINTF_GUID_FORMAT " | " MSG "%.0s", \ + ((SESSION)->header.channel ? ((SESSION)->header.channel->connection ? (SESSION)->header.channel->connection->sockfd : 0) : 0), \ + ((SESSION)->header.channel ? (SESSION)->header.channel->securityToken.channelId : 0), \ + UA_PRINTF_GUID_DATA((SESSION)->sessionId.identifier.guid), __VA_ARGS__) + +#define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_DEBUG_SESSION_INTERNAL(LOGGER, SESSION, __VA_ARGS__, "")) + +#define UA_LOG_INFO_SESSION_INTERNAL(LOGGER, SESSION, MSG, ...) \ + UA_LOG_INFO(LOGGER, UA_LOGCATEGORY_SESSION, \ + "Connection %i | SecureChannel %i | Session " UA_PRINTF_GUID_FORMAT " | " MSG "%.0s", \ + ((SESSION)->header.channel ? ((SESSION)->header.channel->connection ? (SESSION)->header.channel->connection->sockfd : 0) : 0), \ + ((SESSION)->header.channel ? (SESSION)->header.channel->securityToken.channelId : 0), \ + UA_PRINTF_GUID_DATA((SESSION)->sessionId.identifier.guid), __VA_ARGS__) + +#define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_INFO_SESSION_INTERNAL(LOGGER, SESSION, __VA_ARGS__, "")) + +#define UA_LOG_WARNING_SESSION_INTERNAL(LOGGER, SESSION, MSG, ...) \ + UA_LOG_WARNING(LOGGER, UA_LOGCATEGORY_SESSION, \ + "Connection %i | SecureChannel %i | Session " UA_PRINTF_GUID_FORMAT " | " MSG "%.0s", \ + ((SESSION)->header.channel ? ((SESSION)->header.channel->connection ? (SESSION)->header.channel->connection->sockfd : 0) : 0), \ + ((SESSION)->header.channel ? (SESSION)->header.channel->securityToken.channelId : 0), \ + UA_PRINTF_GUID_DATA((SESSION)->sessionId.identifier.guid), __VA_ARGS__) + +#define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_WARNING_SESSION_INTERNAL(LOGGER, SESSION, __VA_ARGS__, "")) + +#define UA_LOG_ERROR_SESSION_INTERNAL(LOGGER, SESSION, MSG, ...) \ + UA_LOG_ERROR(LOGGER, UA_LOGCATEGORY_SESSION, \ + "Connection %i | SecureChannel %i | Session " UA_PRINTF_GUID_FORMAT " | " MSG "%.0s", \ + ((SESSION)->header.channel ? ((SESSION)->header.channel->connection ? (SESSION)->header.channel->connection->sockfd : 0) : 0), \ + ((SESSION)->header.channel ? (SESSION)->header.channel->securityToken.channelId : 0), \ + UA_PRINTF_GUID_DATA((SESSION)->sessionId.identifier.guid), __VA_ARGS__) + +#define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_ERROR_SESSION_INTERNAL(LOGGER, SESSION, __VA_ARGS__, "")) + +#define UA_LOG_FATAL_SESSION_INTERNAL(LOGGER, SESSION, MSG, ...) \ + UA_LOG_FATAL(LOGGER, UA_LOGCATEGORY_SESSION, \ + "Connection %i | SecureChannel %i | Session " UA_PRINTF_GUID_FORMAT " | " MSG "%.0s", \ + ((SESSION)->header.channel ? ((SESSION)->header.channel->connection ? (SESSION)->header.channel->connection->sockfd : 0) : 0), \ + ((SESSION)->header.channel ? (SESSION)->header.channel->securityToken.channelId : 0), \ + UA_PRINTF_GUID_DATA((SESSION)->sessionId.identifier.guid), __VA_ARGS__) + +#define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_FATAL_SESSION_INTERNAL(LOGGER, SESSION, __VA_ARGS__, "")) + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/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-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mattias Bornhager + */ + + + +/** + * 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 + * MonitoredItem that generated the notification. Here we can remove it if the + * 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. + */ + +/*****************/ +/* MonitoredItem */ +/*****************/ + +typedef enum { + UA_MONITOREDITEMTYPE_CHANGENOTIFY = 1, + UA_MONITOREDITEMTYPE_STATUSNOTIFY = 2, + UA_MONITOREDITEMTYPE_EVENTNOTIFY = 4 +} UA_MonitoredItemType; + +/* Not used yet. Placeholder for a future event implementation. */ +typedef struct UA_Event { + UA_Int32 eventId; +} UA_Event; + +struct UA_MonitoredItem; +typedef struct UA_MonitoredItem UA_MonitoredItem; + +typedef struct UA_Notification { + TAILQ_ENTRY(UA_Notification) listEntry; + TAILQ_ENTRY(UA_Notification) globalEntry; + + UA_MonitoredItem *mon; + + /* See the monitoredItemType of the MonitoredItem */ + union { + UA_Event event; + UA_DataValue value; + } data; +} UA_Notification; + +typedef TAILQ_HEAD(NotificationQueue, UA_Notification) NotificationQueue; + +struct UA_MonitoredItem { + LIST_ENTRY(UA_MonitoredItem) listEntry; + UA_Subscription *subscription; + UA_UInt32 monitoredItemId; + UA_UInt32 clientHandle; + + /* Settings */ + UA_MonitoredItemType monitoredItemType; + UA_TimestampsToReturn timestampsToReturn; + UA_MonitoringMode monitoringMode; + UA_NodeId monitoredNodeId; + UA_UInt32 attributeId; + UA_String indexRange; + UA_Double samplingInterval; // [ms] + UA_UInt32 maxQueueSize; + UA_Boolean discardOldest; + // TODO: dataEncoding is hardcoded to UA binary + UA_DataChangeFilter filter; + UA_Variant lastValue; + + /* Sample Callback */ + UA_UInt64 sampleCallbackId; + UA_ByteString lastSampledValue; + UA_Boolean sampleCallbackIsRegistered; + + /* Notification Queue */ + NotificationQueue queue; + UA_UInt32 queueSize; +}; + +UA_MonitoredItem * UA_MonitoredItem_new(UA_MonitoredItemType); +void MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem); +void UA_MonitoredItem_SampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem); +UA_StatusCode MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon); +UA_StatusCode MonitoredItem_unregisterSampleCallback(UA_Server *server, UA_MonitoredItem *mon); + +/* Remove entries until mon->maxQueueSize is reached. Sets infobits for lost + * data if required. */ +void MonitoredItem_ensureQueueSpace(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 */ + /* UA_SUBSCRIPTIONSTATE_CREATING */ + UA_SUBSCRIPTIONSTATE_NORMAL, + UA_SUBSCRIPTIONSTATE_LATE, + UA_SUBSCRIPTIONSTATE_KEEPALIVE +} UA_SubscriptionState; + +typedef TAILQ_HEAD(ListOfNotificationMessages, UA_NotificationMessageEntry) ListOfNotificationMessages; + +struct UA_Subscription { + LIST_ENTRY(UA_Subscription) listEntry; + UA_Session *session; + UA_UInt32 subscriptionId; + + /* Settings */ + UA_UInt32 lifeTimeCount; + UA_UInt32 maxKeepAliveCount; + UA_Double publishingInterval; /* in ms */ + UA_UInt32 notificationsPerPublish; + UA_Boolean publishingEnabled; + UA_UInt32 priority; + + /* Runtime information */ + UA_SubscriptionState state; + UA_UInt32 nextSequenceNumber; + UA_UInt32 currentKeepAliveCount; + UA_UInt32 currentLifetimeCount; + + /* Publish Callback */ + UA_UInt64 publishCallbackId; + UA_Boolean publishCallbackIsRegistered; + + /* MonitoredItems */ + UA_UInt32 lastMonitoredItemId; /* increase the identifiers */ + LIST_HEAD(UA_ListOfUAMonitoredItems, UA_MonitoredItem) monitoredItems; + UA_UInt32 monitoredItemsSize; + + /* Global list of notifications from the MonitoredItems */ + NotificationQueue notificationQueue; + UA_UInt32 notificationQueueSize; + UA_UInt32 readyNotifications; /* Notifications to be sent out now (already late) */ + + /* Retransmission Queue */ + ListOfNotificationMessages retransmissionQueue; + size_t retransmissionQueueSize; +}; + +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); +UA_StatusCode Subscription_unregisterPublishCallback(UA_Server *server, UA_Subscription *sub); +void UA_Subscription_addMonitoredItem(UA_Subscription *sub, UA_MonitoredItem *newMon); +UA_MonitoredItem * UA_Subscription_getMonitoredItem(UA_Subscription *sub, UA_UInt32 monitoredItemId); + +UA_StatusCode +UA_Subscription_deleteMonitoredItem(UA_Server *server, UA_Subscription *sub, + UA_UInt32 monitoredItemId); + +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); + + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/server/ua_session_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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2015 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct session_list_entry { + LIST_ENTRY(session_list_entry) pointers; + UA_Session session; +} session_list_entry; + +typedef struct UA_SessionManager { + LIST_HEAD(session_list, session_list_entry) sessions; // doubly-linked list of sessions + UA_UInt32 currentSessionCount; + UA_Server *server; +} UA_SessionManager; + +UA_StatusCode +UA_SessionManager_init(UA_SessionManager *sm, UA_Server *server); + +/* Deletes all sessions */ +void UA_SessionManager_deleteMembers(UA_SessionManager *sm); + +/* Deletes all sessions that have timed out. Deletion is implemented via a + * delayed callback. So all currently scheduled jobs with a pointer to the + * session can complete. */ +void UA_SessionManager_cleanupTimedOut(UA_SessionManager *sm, + UA_DateTime nowMonotonic); + +UA_StatusCode +UA_SessionManager_createSession(UA_SessionManager *sm, UA_SecureChannel *channel, + const UA_CreateSessionRequest *request, UA_Session **session); + +UA_StatusCode +UA_SessionManager_removeSession(UA_SessionManager *sm, const UA_NodeId *token); + +UA_Session * +UA_SessionManager_getSessionByToken(UA_SessionManager *sm, const UA_NodeId *token); + +UA_Session * +UA_SessionManager_getSessionById(UA_SessionManager *sm, const UA_NodeId *sessionId); + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/server/ua_securechannel_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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct channel_entry { + UA_SecureChannel channel; + TAILQ_ENTRY(channel_entry) pointers; +} channel_entry; + +typedef struct { + TAILQ_HEAD(, channel_entry) channels; // doubly-linked list of channels + UA_UInt32 currentChannelCount; + UA_UInt32 lastChannelId; + UA_UInt32 lastTokenId; + UA_Server *server; +} UA_SecureChannelManager; + +UA_StatusCode +UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_Server *server); + +/* Remove a all securechannels */ +void +UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm); + +/* Remove timed out securechannels with a delayed callback. So all currently + * scheduled jobs with a pointer to a securechannel can finish first. */ +void +UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, + UA_DateTime nowMonotonic); + +UA_StatusCode +UA_SecureChannelManager_create(UA_SecureChannelManager *const cm, UA_Connection *const connection, + const UA_SecurityPolicy *const securityPolicy, + const UA_AsymmetricAlgorithmSecurityHeader *const asymHeader); + +UA_StatusCode +UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_SecureChannel *channel, + const UA_OpenSecureChannelRequest *request, + UA_OpenSecureChannelResponse *response); + +UA_StatusCode +UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_SecureChannel *channel, + const UA_OpenSecureChannelRequest *request, + UA_OpenSecureChannelResponse *response); + +UA_SecureChannel * +UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId); + +UA_StatusCode +UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId); + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Julian Grothoff + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef UA_ENABLE_MULTITHREADING + +#include <pthread.h> + +struct UA_Worker; +typedef struct UA_Worker UA_Worker; + +struct UA_WorkerCallback; +typedef struct UA_WorkerCallback UA_WorkerCallback; + +SIMPLEQ_HEAD(UA_DispatchQueue, UA_WorkerCallback); +typedef struct UA_DispatchQueue UA_DispatchQueue; + +#endif /* UA_ENABLE_MULTITHREADING */ + +#ifdef UA_ENABLE_DISCOVERY + +typedef struct registeredServer_list_entry { + LIST_ENTRY(registeredServer_list_entry) pointers; + UA_RegisteredServer registeredServer; + UA_DateTime lastSeen; +} registeredServer_list_entry; + +typedef struct periodicServerRegisterCallback_entry { + LIST_ENTRY(periodicServerRegisterCallback_entry) pointers; + struct PeriodicServerRegisterCallback *callback; +} periodicServerRegisterCallback_entry; + +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + + +typedef struct serverOnNetwork_list_entry { + LIST_ENTRY(serverOnNetwork_list_entry) pointers; + UA_ServerOnNetwork serverOnNetwork; + UA_DateTime created; + UA_DateTime lastSeen; + UA_Boolean txtSet; + UA_Boolean srvSet; + char* pathTmp; +} serverOnNetwork_list_entry; + +#define SERVER_ON_NETWORK_HASH_PRIME 1009 +typedef struct serverOnNetwork_hash_entry { + serverOnNetwork_list_entry* entry; + struct serverOnNetwork_hash_entry* next; +} serverOnNetwork_hash_entry; + +#endif /* UA_ENABLE_DISCOVERY_MULTICAST */ +#endif /* UA_ENABLE_DISCOVERY */ + +struct UA_Server { + /* Meta */ + UA_DateTime startTime; + + /* Security */ + UA_SecureChannelManager secureChannelManager; + UA_SessionManager sessionManager; + +#ifdef UA_ENABLE_DISCOVERY + /* Discovery */ + LIST_HEAD(registeredServer_list, registeredServer_list_entry) registeredServers; // doubly-linked list of registered servers + size_t registeredServersSize; + LIST_HEAD(periodicServerRegisterCallback_list, periodicServerRegisterCallback_entry) periodicServerRegisterCallbacks; // doubly-linked list of current register callbacks + UA_Server_registerServerCallback registerServerCallback; + void* registerServerCallbackData; +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + mdns_daemon_t *mdnsDaemon; +#ifdef _WIN32 + SOCKET mdnsSocket; +#else + int mdnsSocket; +#endif + UA_Boolean mdnsMainSrvAdded; +# ifdef UA_ENABLE_MULTITHREADING + pthread_t mdnsThread; + UA_Boolean mdnsRunning; +# endif + + LIST_HEAD(serverOnNetwork_list, serverOnNetwork_list_entry) serverOnNetwork; // doubly-linked list of servers on the network (from mDNS) + size_t serverOnNetworkSize; + UA_UInt32 serverOnNetworkRecordIdCounter; + UA_DateTime serverOnNetworkRecordIdLastReset; + // hash mapping domain name to serverOnNetwork list entry + struct serverOnNetwork_hash_entry* serverOnNetworkHash[SERVER_ON_NETWORK_HASH_PRIME]; + + UA_Server_serverOnNetworkCallback serverOnNetworkCallback; + void* serverOnNetworkCallbackData; + +# endif +#endif + + /* Namespaces */ + size_t namespacesSize; + UA_String *namespaces; + + /* Callbacks with a repetition interval */ + UA_Timer timer; + + /* Delayed callbacks */ + SLIST_HEAD(DelayedCallbacksList, UA_DelayedCallback) delayedCallbacks; + + /* Worker threads */ +#ifdef UA_ENABLE_MULTITHREADING + UA_Worker *workers; /* there are nThread workers in a running server */ + UA_DispatchQueue dispatchQueue; /* Dispatch queue for the worker threads */ + pthread_mutex_t dispatchQueue_accessMutex; /* mutex for access to queue */ + pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */ + pthread_mutex_t dispatchQueue_conditionMutex; /* mutex for access to condition variable */ +#endif + + /* For bootstrapping, omit some consistency checks, creating a reference to + * the parent and member instantiation */ + UA_Boolean bootstrapNS0; + + /* Config */ + UA_ServerConfig config; + + /* Local access to the services (for startup and maintenance) uses this + * Session with all possible access rights (Session Id: 1) */ + UA_Session adminSession; +}; + +/*****************/ +/* Node Handling */ +/*****************/ + +#define UA_Nodestore_get(SERVER, NODEID) \ + (SERVER)->config.nodestore.getNode((SERVER)->config.nodestore.context, NODEID) + +#define UA_Nodestore_release(SERVER, NODEID) \ + (SERVER)->config.nodestore.releaseNode((SERVER)->config.nodestore.context, NODEID) + +#define UA_Nodestore_new(SERVER, NODECLASS) \ + (SERVER)->config.nodestore.newNode((SERVER)->config.nodestore.context, NODECLASS) + +#define UA_Nodestore_getCopy(SERVER, NODEID, OUTNODE) \ + (SERVER)->config.nodestore.getNodeCopy((SERVER)->config.nodestore.context, NODEID, OUTNODE) + +#define UA_Nodestore_insert(SERVER, NODE, OUTNODEID) \ + (SERVER)->config.nodestore.insertNode((SERVER)->config.nodestore.context, NODE, OUTNODEID) + +#define UA_Nodestore_delete(SERVER, NODE) \ + (SERVER)->config.nodestore.deleteNode((SERVER)->config.nodestore.context, NODE) + +#define UA_Nodestore_remove(SERVER, NODEID) \ + (SERVER)->config.nodestore.removeNode((SERVER)->config.nodestore.context, NODEID) + +/* 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.*/ +typedef UA_StatusCode (*UA_EditNodeCallback)(UA_Server*, UA_Session*, + UA_Node *node, void*); +UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, + UA_EditNodeCallback callback, + void *data); + +/*************/ +/* Callbacks */ +/*************/ + +/* Delayed callbacks are executed when all previously dispatched callbacks are + * finished */ +UA_StatusCode +UA_Server_delayedCallback(UA_Server *server, UA_ServerCallback callback, void *data); + +UA_StatusCode +UA_Server_delayedFree(UA_Server *server, void *data); + +#ifndef UA_ENABLE_MULTITHREADING +/* Execute all delayed callbacks regardless of whether the worker threads have + * finished previous work */ +void UA_Server_cleanupDelayedCallbacks(UA_Server *server); +#else +void UA_Server_cleanupDispatchQueue(UA_Server *server); +#endif + +/* Callback is executed in the same thread or, if possible, dispatched to one of + * the worker threads. */ +void +UA_Server_workerCallback(UA_Server *server, UA_ServerCallback callback, void *data); + +/*********************/ +/* Utility Functions */ +/*********************/ + +/* A few global NodeId definitions */ +extern const UA_NodeId subtypeId; + +UA_StatusCode +UA_NumericRange_parseFromString(UA_NumericRange *range, const UA_String *str); + +UA_UInt16 addNamespace(UA_Server *server, const UA_String name); + +UA_Boolean +UA_Node_hasSubTypeOrInstances(const UA_Node *node); + +/* Recursively searches "upwards" in the tree following specific reference types */ +UA_Boolean +isNodeInTree(UA_Nodestore *ns, const UA_NodeId *leafNode, + const UA_NodeId *nodeToFind, const UA_NodeId *referenceTypeIds, + size_t referenceTypeIdsSize); + +/* Returns an array with the hierarchy of type nodes. The returned array starts + * at the leaf and continues "upwards" in the hierarchy based on the + * ``hasSubType`` references. Since multiple-inheritance is possible in general, + * duplicate entries are removed. */ +UA_StatusCode +getTypeHierarchy(UA_Nodestore *ns, const UA_NodeId *leafType, + UA_NodeId **typeHierarchy, size_t *typeHierarchySize); + +/* 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); + +/* Many services come as an array of operations. This function generalizes the + * processing of the operations. */ +typedef void (*UA_ServiceOperation)(UA_Server *server, UA_Session *session, + void *context, + const void *requestOperation, + void *responseOperation); + +UA_StatusCode +UA_Server_processServiceOperations(UA_Server *server, UA_Session *session, + UA_ServiceOperation operationCallback, + void *context, + const size_t *requestOperations, + const UA_DataType *requestOperationsType, + size_t *responseOperations, + const UA_DataType *responseOperationsType) + UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +/***************************************/ +/* Check Information Model Consistency */ +/***************************************/ + +UA_StatusCode +readValueAttribute(UA_Server *server, UA_Session *session, + const UA_VariableNode *vn, UA_DataValue *v); + +/* Test whether the value matches a variable definition given by + * - datatype + * - valueranke + * - 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. */ +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); + +UA_Boolean +compatibleArrayDimensions(size_t constraintArrayDimensionsSize, + const UA_UInt32 *constraintArrayDimensions, + size_t testArrayDimensionsSize, + const UA_UInt32 *testArrayDimensions); + +UA_Boolean +compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimensionsSize, + const UA_UInt32 *targetArrayDimensions); + +UA_Boolean +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); + +void +Operation_Browse(UA_Server *server, UA_Session *session, UA_UInt32 *maxrefs, + const UA_BrowseDescription *descr, UA_BrowseResult *result); + +UA_DataValue +UA_Server_readWithSession(UA_Server *server, UA_Session *session, + const UA_ReadValueId *item, + UA_TimestampsToReturn timestampsToReturn); + +/* Checks if a registration timed out and removes that registration. + * Should be called periodically in main loop */ +void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic); + +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + +UA_StatusCode +initMulticastDiscoveryServer(UA_Server* server); + +void startMulticastDiscoveryServer(UA_Server *server); + +void stopMulticastDiscoveryServer(UA_Server *server); + +UA_StatusCode +iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat, + UA_Boolean processIn); + +void destroyMulticastDiscoveryServer(UA_Server* server); + +typedef enum { + UA_DISCOVERY_TCP, /* OPC UA TCP mapping */ + UA_DISCOVERY_TLS /* OPC UA HTTPS mapping */ +} UA_DiscoveryProtocol; + +/* Send a multicast probe to find any other OPC UA server on the network through mDNS. */ +UA_StatusCode +UA_Discovery_multicastQuery(UA_Server* server); + +UA_StatusCode +UA_Discovery_addRecord(UA_Server *server, const UA_String *servername, + const UA_String *hostname, UA_UInt16 port, + const UA_String *path, const UA_DiscoveryProtocol protocol, + UA_Boolean createTxt, const UA_String* capabilites, + size_t *capabilitiesSize); +UA_StatusCode +UA_Discovery_removeRecord(UA_Server *server, const UA_String *servername, + const UA_String *hostname, UA_UInt16 port, + UA_Boolean removeTxt); + +# endif + +/*****************************/ +/* AddNodes Begin and Finish */ +/*****************************/ + +/* Creates a new node in the nodestore. */ +UA_StatusCode +Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext, + const UA_AddNodesItem *item, const UA_NodeId *parentNodeId, + const UA_NodeId *referenceTypeId, + UA_NodeId *outNewNodeId); + +/* Children, references, type-checking, constructors. */ +UA_StatusCode +Operation_addNode_finish(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId); + +/**********************/ +/* Create Namespace 0 */ +/**********************/ + +UA_StatusCode UA_Server_initNS0(UA_Server *server); + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2015 (c) Sten Grüner + * Copyright 2014 (c) LEvertz + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015 (c) Christian Fimmers + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * .. _services: + * + * Services + * ======== + * + * In OPC UA, all communication is based on service calls, each consisting of a + * request and a response message. These messages are defined as data structures + * with a binary encoding and listed in :ref:`generated-types`. Since all + * Services are pre-defined in the standard, they cannot be modified by the + * user. But you can use the :ref:`Call <method-services>` service to invoke + * user-defined methods on the server. + * + * The following service signatures are internal and *not visible to users*. + * Still, we present them here for an overview of the capabilities of OPC UA. + * Please refer to the :ref:`client` and :ref:`server` API where the services + * are exposed to end users. Please see part 4 of the OPC UA standard for the + * authoritative definition of the service and their behaviour. + * + * Most services take as input the server, the current session and pointers to + * the request and response structures. Possible error codes are returned as + * part of the response. */ + +typedef void (*UA_Service)(UA_Server*, UA_Session*, + const void *request, void *response); + +typedef UA_StatusCode (*UA_InSituService)(UA_Server*, UA_Session*, UA_MessageContext *mc, + const void *request, UA_ResponseHeader *rh); + +/** + * Discovery Service Set + * --------------------- + * This Service Set defines Services used to discover the Endpoints implemented + * by a Server and to read the security configuration for those Endpoints. + * + * FindServers Service + * ^^^^^^^^^^^^^^^^^^^ + * Returns the Servers known to a Server or Discovery Server. The Client may + * reduce the number of results returned by specifying filter criteria */ +void Service_FindServers(UA_Server *server, UA_Session *session, + const UA_FindServersRequest *request, + UA_FindServersResponse *response); + +/** + * GetEndpoints Service + * ^^^^^^^^^^^^^^^^^^^^ + * Returns the Endpoints supported by a Server and all of the configuration + * information required to establish a SecureChannel and a Session. */ +void Service_GetEndpoints(UA_Server *server, UA_Session *session, + const UA_GetEndpointsRequest *request, + UA_GetEndpointsResponse *response); + +#ifdef UA_ENABLE_DISCOVERY + +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + +/** + * FindServersOnNetwork Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Returns the Servers known to a Discovery Server. Unlike FindServer, + * this Service is only implemented by Discovery Servers. It additionally + * Returns servery which may have been detected trough Multicast */ +void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session, + const UA_FindServersOnNetworkRequest *request, + UA_FindServersOnNetworkResponse *response); + +# endif /* UA_ENABLE_DISCOVERY_MULTICAST */ + +/** + * RegisterServer + * ^^^^^^^^^^^^^^ + * Registers a remote server in the local discovery service. */ +void Service_RegisterServer(UA_Server *server, UA_Session *session, + const UA_RegisterServerRequest *request, + UA_RegisterServerResponse *response); + +/** + * RegisterServer2 + * ^^^^^^^^^^^^^^^ + * This Service allows a Server to register its DiscoveryUrls and capabilities + * with a Discovery Server. It extends the registration information from + * RegisterServer with information necessary for FindServersOnNetwork. */ +void Service_RegisterServer2(UA_Server *server, UA_Session *session, + const UA_RegisterServer2Request *request, + UA_RegisterServer2Response *response); + +#endif /* UA_ENABLE_DISCOVERY */ + +/** + * SecureChannel Service Set + * ------------------------- + * This Service Set defines Services used to open a communication channel that + * ensures the confidentiality and Integrity of all Messages exchanged with the + * Server. + * + * OpenSecureChannel Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Open or renew a SecureChannel that can be used to ensure Confidentiality and + * Integrity for Message exchange during a Session. */ +void Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel* channel, + const UA_OpenSecureChannelRequest *request, + UA_OpenSecureChannelResponse *response); + +/** + * CloseSecureChannel Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to terminate a SecureChannel. */ +void Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel); + +/** + * Session Service Set + * ------------------- + * This Service Set defines Services for an application layer connection + * establishment in the context of a Session. + * + * CreateSession Service + * ^^^^^^^^^^^^^^^^^^^^^ + * Used by an OPC UA Client to create a Session and the Server returns two + * values which uniquely identify the Session. The first value is the sessionId + * which is used to identify the Session in the audit logs and in the Server's + * address space. The second is the authenticationToken which is used to + * associate an incoming request with a Session. */ +void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, + const UA_CreateSessionRequest *request, + UA_CreateSessionResponse *response); + +/** + * ActivateSession + * ^^^^^^^^^^^^^^^ + * Used by the Client to submit its SoftwareCertificates to the Server for + * validation and to specify the identity of the user associated with the + * Session. This Service request shall be issued by the Client before it issues + * any other Service request after CreateSession. Failure to do so shall cause + * the Server to close the Session. */ +void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, + UA_Session *session, + const UA_ActivateSessionRequest *request, + UA_ActivateSessionResponse *response); + +/** + * CloseSession + * ^^^^^^^^^^^^ + * Used to terminate a Session. */ +void Service_CloseSession(UA_Server *server, UA_Session *session, + const UA_CloseSessionRequest *request, + UA_CloseSessionResponse *response); + +/** + * Cancel Service + * ^^^^^^^^^^^^^^ + * Used to cancel outstanding Service requests. Successfully cancelled service + * requests shall respond with Bad_RequestCancelledByClient. */ +/* Not Implemented */ + +/** + * NodeManagement Service Set + * -------------------------- + * This Service Set defines Services to add and delete AddressSpace Nodes and + * References between them. All added Nodes continue to exist in the + * AddressSpace even if the Client that created them disconnects from the + * Server. + * + * AddNodes Service + * ^^^^^^^^^^^^^^^^ + * Used to add one or more Nodes into the AddressSpace hierarchy. */ +void Service_AddNodes(UA_Server *server, UA_Session *session, + const UA_AddNodesRequest *request, + UA_AddNodesResponse *response); + +/** + * AddReferences Service + * ^^^^^^^^^^^^^^^^^^^^^ + * 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); + +/** + * DeleteNodes Service + * ^^^^^^^^^^^^^^^^^^^ + * Used to delete one or more Nodes from the AddressSpace. */ +void Service_DeleteNodes(UA_Server *server, UA_Session *session, + const UA_DeleteNodesRequest *request, + UA_DeleteNodesResponse *response); + +/** + * DeleteReferences + * ^^^^^^^^^^^^^^^^ + * Used to delete one or more References of a Node. */ +void Service_DeleteReferences(UA_Server *server, UA_Session *session, + const UA_DeleteReferencesRequest *request, + UA_DeleteReferencesResponse *response); + +/** + * .. _view-services: + * + * View Service Set + * ---------------- + * Clients use the browse Services of the View Service Set to navigate through + * the AddressSpace or through a View which is a subset of the AddressSpace. + * + * Browse Service + * ^^^^^^^^^^^^^^ + * Used to discover the References of a specified Node. The browse can be + * further limited by the use of a View. This Browse Service also supports a + * primitive filtering capability. */ +void Service_Browse(UA_Server *server, UA_Session *session, + const UA_BrowseRequest *request, + UA_BrowseResponse *response); + +/** + * BrowseNext Service + * ^^^^^^^^^^^^^^^^^^ + * Used to request the next set of Browse or BrowseNext response information + * that is too large to be sent in a single response. "Too large" in this + * context means that the Server is not able to return a larger response or that + * the number of results to return exceeds the maximum number of results to + * return that was specified by the Client in the original Browse request. */ +void Service_BrowseNext(UA_Server *server, UA_Session *session, + const UA_BrowseNextRequest *request, + UA_BrowseNextResponse *response); + +/** + * TranslateBrowsePathsToNodeIds Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to translate textual node paths to their respective ids. */ +void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session, + const UA_TranslateBrowsePathsToNodeIdsRequest *request, + UA_TranslateBrowsePathsToNodeIdsResponse *response); + +/** + * RegisterNodes Service + * ^^^^^^^^^^^^^^^^^^^^^ + * Used by Clients to register the Nodes that they know they will access + * repeatedly (e.g. Write, Call). It allows Servers to set up anything needed so + * that the access operations will be more efficient. */ +void Service_RegisterNodes(UA_Server *server, UA_Session *session, + const UA_RegisterNodesRequest *request, + UA_RegisterNodesResponse *response); + +/** + * UnregisterNodes Service + * ^^^^^^^^^^^^^^^^^^^^^^^ + * This Service is used to unregister NodeIds that have been obtained via the + * RegisterNodes service. */ +void Service_UnregisterNodes(UA_Server *server, UA_Session *session, + const UA_UnregisterNodesRequest *request, + UA_UnregisterNodesResponse *response); + +/** + * Query Service Set + * ----------------- + * This Service Set is used to issue a Query to a Server. OPC UA Query is + * generic in that it provides an underlying storage mechanism independent Query + * capability that can be used to access a wide variety of OPC UA data stores + * and information management systems. OPC UA Query permits a Client to access + * data maintained by a Server without any knowledge of the logical schema used + * for internal storage of the data. Knowledge of the AddressSpace is + * sufficient. + * + * QueryFirst Service + * ^^^^^^^^^^^^^^^^^^ + * This Service is used to issue a Query request to the Server. */ +/* Not Implemented */ + +/** + * QueryNext Service + * ^^^^^^^^^^^^^^^^^ + * This Service is used to request the next set of QueryFirst or QueryNext + * response information that is too large to be sent in a single response. */ +/* Not Impelemented */ + +/** + * Attribute Service Set + * --------------------- + * This Service Set provides Services to access Attributes that are part of + * Nodes. + * + * Read Service + * ^^^^^^^^^^^^ + * Used to read attributes of nodes. For constructed attribute values whose + * elements are indexed, such as an array, this Service allows Clients to read + * the entire set of indexed values as a composite, to read individual elements + * or to read ranges of elements of the composite. */ +UA_StatusCode Service_Read(UA_Server *server, UA_Session *session, UA_MessageContext *mc, + const UA_ReadRequest *request, UA_ResponseHeader *responseHeader); + +/** + * Write Service + * ^^^^^^^^^^^^^ + * Used to write attributes of nodes. For constructed attribute values whose + * elements are indexed, such as an array, this Service allows Clients to write + * the entire set of indexed values as a composite, to write individual elements + * or to write ranges of elements of the composite. */ +void Service_Write(UA_Server *server, UA_Session *session, + const UA_WriteRequest *request, + UA_WriteResponse *response); + +/** + * HistoryRead Service + * ^^^^^^^^^^^^^^^^^^^ + * Used to read historical values or Events of one or more Nodes. Servers may + * make historical values available to Clients using this Service, although the + * historical values themselves are not visible in the AddressSpace. */ +/* Not Implemented */ + +/** + * HistoryUpdate Service + * ^^^^^^^^^^^^^^^^^^^^^ + * Used to update historical values or Events of one or more Nodes. Several + * request parameters indicate how the Server is to update the historical value + * or Event. Valid actions are Insert, Replace or Delete. */ +/* Not Implemented */ + +/** + * .. _method-services: + * + * Method Service Set + * ------------------ + * The Method Service Set defines the means to invoke methods. A method shall be + * a component of an Object. See the section on :ref:`MethodNodes <methodnode>` + * for more information. + * + * Call Service + * ^^^^^^^^^^^^ + * Used to call (invoke) a methods. Each method call is invoked within the + * context of an existing Session. If the Session is terminated, the results of + * the method's execution cannot be returned to the Client and are discarded. */ +void Service_Call(UA_Server *server, UA_Session *session, + const UA_CallRequest *request, + UA_CallResponse *response); + +/** + * MonitoredItem Service Set + * ------------------------- + * Clients define MonitoredItems to subscribe to data and Events. Each + * MonitoredItem identifies the item to be monitored and the Subscription to use + * to send Notifications. The item to be monitored may be any Node Attribute. + * + * CreateMonitoredItems Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to create and add one or more MonitoredItems to a Subscription. A + * MonitoredItem is deleted automatically by the Server when the Subscription is + * deleted. Deleting a MonitoredItem causes its entire set of triggered item + * links to be deleted, but has no effect on the MonitoredItems referenced by + * the triggered items. */ +void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session, + const UA_CreateMonitoredItemsRequest *request, + UA_CreateMonitoredItemsResponse *response); + +/** + * DeleteMonitoredItems Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to remove one or more MonitoredItems of a Subscription. When a + * MonitoredItem is deleted, its triggered item links are also deleted. */ +void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session, + const UA_DeleteMonitoredItemsRequest *request, + UA_DeleteMonitoredItemsResponse *response); + +/** + * ModifyMonitoredItems Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to modify MonitoredItems of a Subscription. Changes to the MonitoredItem + * settings shall be applied immediately by the Server. They take effect as soon + * as practical but not later than twice the new revisedSamplingInterval. + * + * Illegal request values for parameters that can be revised do not generate + * errors. Instead the server will choose default values and indicate them in + * the corresponding revised parameter. */ +void Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session, + const UA_ModifyMonitoredItemsRequest *request, + UA_ModifyMonitoredItemsResponse *response); + +/** + * SetMonitoringMode Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to set the monitoring mode for one or more MonitoredItems of a + * Subscription. */ +void Service_SetMonitoringMode(UA_Server *server, UA_Session *session, + const UA_SetMonitoringModeRequest *request, + UA_SetMonitoringModeResponse *response); + +/** + * SetTriggering Service + * ^^^^^^^^^^^^^^^^^^^^^ + * Used to create and delete triggering links for a triggering item. */ +/* Not Implemented */ + +/** + * Subscription Service Set + * ------------------------ + * Subscriptions are used to report Notifications to the Client. + * + * CreateSubscription Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to create a Subscription. Subscriptions monitor a set of MonitoredItems + * for Notifications and return them to the Client in response to Publish + * requests. */ +void Service_CreateSubscription(UA_Server *server, UA_Session *session, + const UA_CreateSubscriptionRequest *request, + UA_CreateSubscriptionResponse *response); + +/** + * ModifySubscription Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to modify a Subscription. */ +void Service_ModifySubscription(UA_Server *server, UA_Session *session, + const UA_ModifySubscriptionRequest *request, + UA_ModifySubscriptionResponse *response); + +/** + * SetPublishingMode Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to enable sending of Notifications on one or more Subscriptions. */ +void Service_SetPublishingMode(UA_Server *server, UA_Session *session, + const UA_SetPublishingModeRequest *request, + UA_SetPublishingModeResponse *response); + +/** + * Publish Service + * ^^^^^^^^^^^^^^^ + * Used for two purposes. First, it is used to acknowledge the receipt of + * NotificationMessages for one or more Subscriptions. Second, it is used to + * request the Server to return a NotificationMessage or a keep-alive + * Message. + * + * 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); + +/** + * Republish Service + * ^^^^^^^^^^^^^^^^^ + * Requests the Subscription to republish a NotificationMessage from its + * retransmission queue. */ +void Service_Republish(UA_Server *server, UA_Session *session, + const UA_RepublishRequest *request, + UA_RepublishResponse *response); + +/** + * DeleteSubscriptions Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Invoked to delete one or more Subscriptions that belong to the Client's + * Session. */ +void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session, + const UA_DeleteSubscriptionsRequest *request, + UA_DeleteSubscriptionsResponse *response); + +/** + * TransferSubscription Service + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Used to transfer a Subscription and its MonitoredItems from one Session to + * another. For example, a Client may need to reopen a Session and then transfer + * 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 */ + +#ifdef __cplusplus +} // extern "C" +#endif + + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_namespace0.h" ***********************************/ + +/* WARNING: This is a generated file. + * Any manual changes will be overwritten. */ + +#ifndef UA_NAMESPACE0_H_ +#define UA_NAMESPACE0_H_ + + +#ifdef UA_NO_AMALGAMATION +#else + +/* The following declarations are in the open62541.c file so here's needed when compiling nodesets externally */ + +# ifndef UA_Nodestore_remove //this definition is needed to hide this code in the amalgamated .c file + +typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos, + const UA_Byte **bufEnd); + +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; + +UA_StatusCode +UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, + const UA_DataType *type, size_t customTypesSize, + const UA_DataType *customTypes) UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +size_t +UA_calcSizeBinary(void *p, const UA_DataType *type); + +const UA_DataType * +UA_findDataTypeByBinary(const UA_NodeId *typeId); + +# endif // UA_Nodestore_remove + +#endif + + + + +#ifdef __cplusplus +extern "C" { +#endif + +extern UA_StatusCode ua_namespace0(UA_Server *server); + +#ifdef __cplusplus +} +#endif + +#endif /* UA_NAMESPACE0_H_ */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + + +/**************************/ +/* Subscriptions Handling */ +/**************************/ + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +typedef struct UA_Client_NotificationsAckNumber { + LIST_ENTRY(UA_Client_NotificationsAckNumber) listEntry; + UA_SubscriptionAcknowledgement subAck; +} UA_Client_NotificationsAckNumber; + +typedef struct UA_Client_MonitoredItem { + LIST_ENTRY(UA_Client_MonitoredItem) listEntry; + UA_UInt32 monitoredItemId; + UA_UInt32 clientHandle; + void *context; + UA_Client_DeleteMonitoredItemCallback deleteCallback; + union { + UA_Client_DataChangeNotificationCallback dataChangeCallback; + UA_Client_EventNotificationCallback eventCallback; + } handler; + UA_Boolean isEventMonitoredItem; /* Otherwise a DataChange MoniitoredItem */ +} UA_Client_MonitoredItem; + +typedef struct UA_Client_Subscription { + LIST_ENTRY(UA_Client_Subscription) listEntry; + UA_UInt32 subscriptionId; + void *context; + UA_Double publishingInterval; + UA_UInt32 maxKeepAliveCount; + UA_Client_StatusChangeNotificationCallback statusChangeCallback; + UA_Client_DeleteSubscriptionCallback deleteCallback; + UA_UInt32 sequenceNumber; + UA_DateTime lastActivity; + LIST_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem) monitoredItems; +} UA_Client_Subscription; + +void +UA_Client_Subscriptions_clean(UA_Client *client); + +void +UA_Client_MonitoredItem_remove(UA_Client *client, UA_Client_Subscription *sub, + UA_Client_MonitoredItem *mon); + +void +UA_Client_Subscriptions_processPublishResponse(UA_Client *client, + UA_PublishRequest *request, + UA_PublishResponse *response); + +UA_StatusCode +UA_Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request); + +UA_StatusCode +UA_Client_Subscriptions_backgroundPublish(UA_Client *client); + +void +UA_Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client); + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/**********/ +/* Client */ +/**********/ + +typedef struct AsyncServiceCall { + LIST_ENTRY(AsyncServiceCall) pointers; + UA_UInt32 requestId; + UA_ClientAsyncServiceCallback callback; + const UA_DataType *responseType; + void *userdata; + UA_DateTime start; + UA_UInt32 timeout; +} AsyncServiceCall; + +void UA_Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac, + UA_StatusCode statusCode); + +void UA_Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode); + +typedef enum { + UA_CLIENTAUTHENTICATION_NONE, + UA_CLIENTAUTHENTICATION_USERNAME +} UA_Client_Authentication; + +struct UA_Client { + /* State */ + UA_ClientState state; + + UA_ClientConfig config; + + /* Connection */ + UA_Connection connection; + UA_String endpointUrl; + + /* SecureChannel */ + UA_SecurityPolicy securityPolicy; /* TODO: Move supported policies to the config */ + UA_SecureChannel channel; + UA_UInt32 requestId; + UA_DateTime nextChannelRenewal; + + /* Authentication */ + UA_Client_Authentication authenticationMethod; + UA_String username; + UA_String password; + + /* Session */ + UA_UserTokenPolicy token; + UA_NodeId authenticationToken; + UA_UInt32 requestHandle; + + /* Async Service */ + LIST_HEAD(ListOfAsyncServiceCall, AsyncServiceCall) asyncServiceCalls; + + /* Subscriptions */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_UInt32 monitoredItemHandles; + LIST_HEAD(ListOfUnacknowledgedNotifications, UA_Client_NotificationsAckNumber) pendingNotificationsAcks; + LIST_HEAD(ListOfClientSubscriptionItems, UA_Client_Subscription) subscriptions; + UA_UInt16 currentlyOutStandingPublishRequests; +#endif + + /* Connectivity check */ + UA_DateTime lastConnectivityCheck; + UA_Boolean pendingConnectivityCheck; +}; + +void +setClientState(UA_Client *client, UA_ClientState state); + +UA_StatusCode +UA_Client_connectInternal(UA_Client *client, const char *endpointUrl, + UA_Boolean endpointsHandshake, UA_Boolean createNewSession); + +UA_StatusCode +UA_Client_getEndpointsInternal(UA_Client *client, size_t* endpointDescriptionsSize, + UA_EndpointDescription** endpointDescriptions); + +/* Receive and process messages until a synchronous message arrives or the + * timout finishes */ +UA_StatusCode +receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *responseType, + UA_DateTime maxDate, UA_UInt32 *synchronousRequestId); + + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2016-2017 (c) Florian Palm + * Copyright 2014-2016 (c) Sten Grüner + * Copyright 2014 (c) Leon Urbas + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015 (c) Markus Graube + * Copyright 2015 (c) Reza Ebrahimi + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) Lorenz Haas + */ + + + +/* Datatype Handling + * ----------------- + * This file contains handling functions for the builtin types and functions + * handling of structured types and arrays. These need type descriptions in a + * UA_DataType structure. The UA_DataType structures as well as all non-builtin + * datatypes are autogenerated. */ + +/* 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}; + +/* 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; + + /* 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].typeId.identifier.numeric == typeId->identifier.numeric + && UA_TYPES[i].typeId.namespaceIndex == typeId->namespaceIndex) + 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]; + } + }*/ + + return NULL; +} + +/***************************/ +/* Random Number Generator */ +/***************************/ + +//TODO is this safe for multithreading? +static pcg32_random_t UA_rng = PCG32_INITIALIZER; + +void +UA_random_seed(u64 seed) { + pcg32_srandom_r(&UA_rng, seed, (u64)UA_DateTime_now()); +} + +u32 +UA_UInt32_random(void) { + return (u32)pcg32_random_r(&UA_rng); +} + +/*****************/ +/* Builtin Types */ +/*****************/ + +static void deleteMembers_noInit(void *p, const UA_DataType *type); +static UA_StatusCode copy_noInit(const void *src, void *dst, const UA_DataType *type); + +UA_String +UA_String_fromChars(char const src[]) { + UA_String str; + str.length = strlen(src); + if(str.length > 0) { + str.data = (u8*)UA_malloc(str.length); + if(!str.data) + return UA_STRING_NULL; + memcpy(str.data, src, str.length); + } else { + str.data = (u8*)UA_EMPTY_ARRAY_SENTINEL; + } + return str; +} + +UA_Boolean +UA_String_equal(const UA_String *s1, const UA_String *s2) { + if(s1->length != s2->length) + return false; + i32 is = memcmp((char const*)s1->data, + (char const*)s2->data, s1->length); + return (is == 0) ? true : false; +} + +static void +String_deleteMembers(UA_String *s, const UA_DataType *_) { + UA_free((void*)((uintptr_t)s->data & ~(uintptr_t)UA_EMPTY_ARRAY_SENTINEL)); +} + +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); +} + +/* DateTime */ +UA_DateTimeStruct +UA_DateTime_toStruct(UA_DateTime t) { + /* Calculating the the milli-, micro- and nanoseconds */ + UA_DateTimeStruct dateTimeStruct; + dateTimeStruct.nanoSec = (u16)((t % 10) * 100); + dateTimeStruct.microSec = (u16)((t % 10000) / 10); + dateTimeStruct.milliSec = (u16)((t % 10000000) / 10000); + + /* Calculating the unix time with #include <time.h> */ + long long secSinceUnixEpoch = (long long) + ((t - UA_DATETIME_UNIX_EPOCH) / 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; + dateTimeStruct.month = (u16)(ts.tm_mon + 1); + dateTimeStruct.year = (u16)(ts.tm_year + 1900); + return dateTimeStruct; +} + +static void +printNumber(u16 n, u8 *pos, size_t digits) { + for(size_t i = digits; i > 0; --i) { + pos[i-1] = (u8)((n % 10) + '0'); + n = n / 10; + } +} + +UA_String +UA_DateTime_toString(UA_DateTime t) { + /* length of the string is 31 (plus \0 at the end) */ + UA_String str = {31, (u8*)UA_malloc(32)}; + if(!str.data) + return UA_STRING_NULL; + UA_DateTimeStruct tSt = UA_DateTime_toStruct(t); + printNumber(tSt.month, str.data, 2); + str.data[2] = '/'; + printNumber(tSt.day, &str.data[3], 2); + str.data[5] = '/'; + printNumber(tSt.year, &str.data[6], 4); + str.data[10] = ' '; + printNumber(tSt.hour, &str.data[11], 2); + str.data[13] = ':'; + printNumber(tSt.min, &str.data[14], 2); + str.data[16] = ':'; + printNumber(tSt.sec, &str.data[17], 2); + str.data[19] = '.'; + printNumber(tSt.milliSec, &str.data[20], 3); + str.data[23] = '.'; + printNumber(tSt.microSec, &str.data[24], 3); + str.data[27] = '.'; + printNumber(tSt.nanoSec, &str.data[28], 3); + return str; +} + +/* 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; +} + +UA_Guid +UA_Guid_random(void) { + UA_Guid result; + result.data1 = (u32)pcg32_random_r(&UA_rng); + u32 r = (u32)pcg32_random_r(&UA_rng); + result.data2 = (u16) r; + result.data3 = (u16) (r >> 16); + r = (u32)pcg32_random_r(&UA_rng); + result.data4[0] = (u8)r; + result.data4[1] = (u8)(r >> 4); + result.data4[2] = (u8)(r >> 8); + result.data4[3] = (u8)(r >> 12); + r = (u32)pcg32_random_r(&UA_rng); + result.data4[4] = (u8)r; + result.data4[5] = (u8)(r >> 4); + result.data4[6] = (u8)(r >> 8); + result.data4[7] = (u8)(r >> 12); + return result; +} + +/* ByteString */ +UA_StatusCode +UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) { + UA_ByteString_init(bs); + if(length == 0) + return UA_STATUSCODE_GOOD; + bs->data = (u8*)UA_malloc(length); + if(!bs->data) + return UA_STATUSCODE_BADOUTOFMEMORY; + bs->length = length; + return UA_STATUSCODE_GOOD; +} + +/* NodeId */ +static void +NodeId_deleteMembers(UA_NodeId *p, const UA_DataType *_) { + switch(p->identifierType) { + case UA_NODEIDTYPE_STRING: + case UA_NODEIDTYPE_BYTESTRING: + String_deleteMembers(&p->identifier.string, NULL); + break; + default: break; + } +} + +static UA_StatusCode +NodeId_copy(UA_NodeId const *src, UA_NodeId *dst, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + switch(src->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + *dst = *src; + return UA_STATUSCODE_GOOD; + case UA_NODEIDTYPE_STRING: + retval |= UA_String_copy(&src->identifier.string, + &dst->identifier.string); + break; + case UA_NODEIDTYPE_GUID: + retval |= UA_Guid_copy(&src->identifier.guid, &dst->identifier.guid); + break; + case UA_NODEIDTYPE_BYTESTRING: + retval |= UA_ByteString_copy(&src->identifier.byteString, + &dst->identifier.byteString); + break; + default: + return UA_STATUSCODE_BADINTERNALERROR; + } + dst->namespaceIndex = src->namespaceIndex; + dst->identifierType = src->identifierType; + return retval; +} + +UA_Boolean +UA_NodeId_isNull(const UA_NodeId *p) { + if(p->namespaceIndex != 0) + return false; + switch(p->identifierType) { + 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_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; +} + +UA_Boolean +UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) { + if(n1 == NULL || n2 == NULL) + return false; + if(n1->namespaceIndex != n2->namespaceIndex || + n1->identifierType!=n2->identifierType) + return false; + switch(n1->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + return (n1->identifier.numeric == n2->identifier.numeric); + case UA_NODEIDTYPE_STRING: + return UA_String_equal(&n1->identifier.string, + &n2->identifier.string); + case UA_NODEIDTYPE_GUID: + return UA_Guid_equal(&n1->identifier.guid, + &n2->identifier.guid); + case UA_NODEIDTYPE_BYTESTRING: + return UA_ByteString_equal(&n1->identifier.byteString, + &n2->identifier.byteString); + } + return false; +} + +UA_Boolean +UA_ExpandedNodeId_equal(const UA_ExpandedNodeId *n1, const UA_ExpandedNodeId *n2) { + if(n1 == NULL || n2 == NULL) + return false; + if(n1->serverIndex != n2->serverIndex) + return false; + if(!UA_String_equal(&n1->namespaceUri, &n2->namespaceUri)) + return false; + return UA_NodeId_equal(&n1->nodeId, &n2->nodeId); +} + +/* 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 +static u32 +fnv32(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; +} + +u32 +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 */ + case UA_NODEIDTYPE_STRING: + case UA_NODEIDTYPE_BYTESTRING: + return fnv32(n->namespaceIndex, n->identifier.string.data, n->identifier.string.length); + case UA_NODEIDTYPE_GUID: + return fnv32(n->namespaceIndex, (const u8*)&n->identifier.guid, sizeof(UA_Guid)); + } +} + +/* ExpandedNodeId */ +static void +ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p, const UA_DataType *_) { + NodeId_deleteMembers(&p->nodeId, _); + String_deleteMembers(&p->namespaceUri, NULL); +} + +static UA_StatusCode +ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNodeId *dst, + const UA_DataType *_) { + UA_StatusCode retval = NodeId_copy(&src->nodeId, &dst->nodeId, NULL); + retval |= UA_String_copy(&src->namespaceUri, &dst->namespaceUri); + dst->serverIndex = src->serverIndex; + return retval; +} + +/* ExtensionObject */ +static void +ExtensionObject_deleteMembers(UA_ExtensionObject *p, const UA_DataType *_) { + switch(p->encoding) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + case UA_EXTENSIONOBJECT_ENCODED_XML: + NodeId_deleteMembers(&p->content.encoded.typeId, NULL); + String_deleteMembers(&p->content.encoded.body, NULL); + break; + case UA_EXTENSIONOBJECT_DECODED: + if(p->content.decoded.data) + UA_delete(p->content.decoded.data, p->content.decoded.type); + break; + default: + break; + } +} + +static UA_StatusCode +ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst, + const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + switch(src->encoding) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + case UA_EXTENSIONOBJECT_ENCODED_XML: + dst->encoding = src->encoding; + retval = NodeId_copy(&src->content.encoded.typeId, + &dst->content.encoded.typeId, NULL); + retval |= UA_ByteString_copy(&src->content.encoded.body, + &dst->content.encoded.body); + break; + case UA_EXTENSIONOBJECT_DECODED: + case UA_EXTENSIONOBJECT_DECODED_NODELETE: + if(!src->content.decoded.type || !src->content.decoded.data) + return UA_STATUSCODE_BADINTERNALERROR; + dst->encoding = UA_EXTENSIONOBJECT_DECODED; + dst->content.decoded.type = src->content.decoded.type; + retval = UA_Array_copy(src->content.decoded.data, 1, + &dst->content.decoded.data, src->content.decoded.type); + break; + default: + break; + } + return retval; +} + +/* Variant */ +static void +Variant_deletemembers(UA_Variant *p, const UA_DataType *_) { + if(p->storageType != UA_VARIANT_DATA) + return; + 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; + } + if((void*)p->arrayDimensions > UA_EMPTY_ARRAY_SENTINEL) + UA_free(p->arrayDimensions); +} + +static UA_StatusCode +Variant_copy(UA_Variant const *src, UA_Variant *dst, const UA_DataType *_) { + size_t length = src->arrayLength; + if(UA_Variant_isScalar(src)) + length = 1; + UA_StatusCode retval = UA_Array_copy(src->data, length, + &dst->data, src->type); + if(retval != UA_STATUSCODE_GOOD) + return retval; + dst->arrayLength = src->arrayLength; + dst->type = src->type; + if(src->arrayDimensions) { + 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; + } + return UA_STATUSCODE_GOOD; +} + +void +UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, + const UA_DataType *type) { + UA_Variant_init(v); + v->type = type; + v->arrayLength = 0; + v->data = p; +} + +UA_StatusCode +UA_Variant_setScalarCopy(UA_Variant *v, const void *p, + const UA_DataType *type) { + void *n = UA_malloc(type->memSize); + if(!n) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_StatusCode retval = UA_copy(p, n, type); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(n); + //cppcheck-suppress memleak + return retval; + } + UA_Variant_setScalar(v, n, type); + //cppcheck-suppress memleak + return UA_STATUSCODE_GOOD; +} + +void UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, + size_t arraySize, const UA_DataType *type) { + UA_Variant_init(v); + v->data = array; + v->arrayLength = arraySize; + v->type = type; +} + +UA_StatusCode +UA_Variant_setArrayCopy(UA_Variant *v, const void *array, + size_t arraySize, const UA_DataType *type) { + UA_Variant_init(v); + UA_StatusCode retval = UA_Array_copy(array, arraySize, &v->data, type); + if(retval != UA_STATUSCODE_GOOD) + return retval; + v->arrayLength = arraySize; + v->type = type; + 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 */ +static UA_StatusCode +computeStrides(const UA_Variant *v, const UA_NumericRange range, + size_t *total, size_t *block, size_t *stride, size_t *first) { + /* 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; + } + UA_assert(dims_count > 0); + + /* Test the integrity of the range and compute the max index used for every + * dimension. The standard says in Part 4, Section 7.22: + * + * 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; + UA_STACKARRAY(UA_UInt32, realmax, dims_count); + 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) + return UA_STATUSCODE_BADINDEXRANGEINVALID; + 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; + } + + *total = count; + + /* 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. */ + *first = 0; + size_t running_dimssize = 1; + bool found_contiguous = false; + for(size_t k = dims_count; k > 0;) { + --k; + size_t dimrange = 1 + realmax[k] - range.dimensions[k].min; + if(!found_contiguous && dimrange != dims[k]) { + /* Found the maximum block that can be copied contiguously */ + found_contiguous = true; + *block = running_dimssize * dimrange; + *stride = running_dimssize * dims[k]; + } + *first += running_dimssize * range.dimensions[k].min; + running_dimssize *= dims[k]; + } + return UA_STATUSCODE_GOOD; +} + +/* Is the type string-like? */ +static bool +isStringLike(const UA_DataType *type) { + if(type->membersSize == 1 && type->members[0].isArray && + type->members[0].namespaceZero && + type->members[0].memberTypeIndex == UA_TYPES_BYTE) + return true; + return false; +} + +/* Returns the part of the string that lies within the rangedimension */ +static UA_StatusCode +copySubString(const UA_String *src, UA_String *dst, + const UA_NumericRangeDimension *dim) { + if(dim->min > dim->max) + return UA_STATUSCODE_BADINDEXRANGEINVALID; + if(dim->min >= src->length) + return UA_STATUSCODE_BADINDEXRANGENODATA; + + size_t length; + if(dim->max < src->length) + length = dim->max - dim->min + 1; + else + length = src->length - dim->min; + + UA_StatusCode retval = UA_ByteString_allocBuffer(dst, length); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + memcpy(dst->data, &src->data[dim->min], length); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, + const UA_NumericRange range) { + if(!src->type) + return UA_STATUSCODE_BADINVALIDARGUMENT; + bool isScalar = UA_Variant_isScalar(src); + bool stringLike = isStringLike(src->type); + UA_Variant arraySrc; + + /* 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 */ + if(isScalar) { + /* Replace scalar src with array of length 1 */ + arraySrc = *src; + arraySrc.arrayLength = 1; + src = &arraySrc; + /* Deal with all range dimensions within the scalar */ + thisrange.dimensions = &scalarThisDimension; + thisrange.dimensionsSize = 1; + nextrange = range; + } else { + /* Deal with as many range dimensions as possible right now */ + size_t dims = src->arrayDimensionsSize; + if(dims == 0) + 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); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Allocate the array */ + UA_Variant_init(dst); + dst->data = UA_Array_new(count, src->type); + if(!dst->data) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Copy the range */ + size_t block_count = count / block; + size_t elem_size = src->type->memSize; + uintptr_t nextdst = (uintptr_t)dst->data; + uintptr_t nextsrc = (uintptr_t)src->data + (elem_size * first); + if(nextrange.dimensionsSize == 0) { + /* no nextrange */ + if(src->type->pointerFree) { + for(size_t i = 0; i < block_count; ++i) { + memcpy((void*)nextdst, (void*)nextsrc, elem_size * block); + nextdst += block * elem_size; + nextsrc += stride * elem_size; + } + } else { + for(size_t i = 0; i < block_count; ++i) { + for(size_t j = 0; j < block; ++j) { + retval = UA_copy((const void*)nextsrc, + (void*)nextdst, src->type); + nextdst += elem_size; + nextsrc += elem_size; + } + nextsrc += (stride - block) * elem_size; + } + } + } else { + /* nextrange can only be used for variants and stringlike with remaining + * range of dimension 1 */ + if(src->type != &UA_TYPES[UA_TYPES_VARIANT]) { + if(!stringLike) + retval = UA_STATUSCODE_BADINDEXRANGENODATA; + if(nextrange.dimensionsSize != 1) + retval = UA_STATUSCODE_BADINDEXRANGENODATA; + } + + /* Copy the content */ + for(size_t i = 0; i < block_count; ++i) { + for(size_t j = 0; j < block && retval == UA_STATUSCODE_GOOD; ++j) { + if(stringLike) + retval = copySubString((const UA_String*)nextsrc, + (UA_String*)nextdst, + nextrange.dimensions); + else + retval = UA_Variant_copyRange((const UA_Variant*)nextsrc, + (UA_Variant*)nextdst, + nextrange); + nextdst += elem_size; + nextsrc += elem_size; + } + nextsrc += (stride - block) * elem_size; + } + } + + /* Clean up if copying failed */ + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(dst->data, count, src->type); + dst->data = NULL; + return retval; + } + + /* Done if scalar */ + dst->type = src->type; + if(isScalar) + return retval; + + /* Copy array dimensions */ + dst->arrayLength = count; + if(src->arrayDimensionsSize > 0) { + dst->arrayDimensions = + (u32*)UA_Array_new(thisrange.dimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); + if(!dst->arrayDimensions) { + Variant_deletemembers(dst, NULL); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + dst->arrayDimensionsSize = thisrange.dimensionsSize; + for(size_t k = 0; k < thisrange.dimensionsSize; ++k) + dst->arrayDimensions[k] = + thisrange.dimensions[k].max - thisrange.dimensions[k].min + 1; + } + return UA_STATUSCODE_GOOD; +} + +/* TODO: Allow ranges to reach inside a scalars that are array-like, e.g. + * variant and strings. This is already possible for reading... */ +static UA_StatusCode +Variant_setRange(UA_Variant *v, void *array, size_t arraySize, + const UA_NumericRange range, bool copy) { + /* Compute the strides */ + size_t count, block, stride, first; + UA_StatusCode retval = computeStrides(v, range, &count, + &block, &stride, &first); + if(retval != UA_STATUSCODE_GOOD) + return retval; + if(count != arraySize) + return UA_STATUSCODE_BADINDEXRANGEINVALID; + + /* Move/copy the elements */ + size_t block_count = count / block; + size_t elem_size = v->type->memSize; + uintptr_t nextdst = (uintptr_t)v->data + (first * elem_size); + uintptr_t nextsrc = (uintptr_t)array; + if(v->type->pointerFree || !copy) { + for(size_t i = 0; i < block_count; ++i) { + memcpy((void*)nextdst, (void*)nextsrc, elem_size * block); + nextsrc += block * elem_size; + nextdst += stride * elem_size; + } + } else { + for(size_t i = 0; i < block_count; ++i) { + for(size_t j = 0; j < block; ++j) { + deleteMembers_noInit((void*)nextdst, v->type); + retval |= UA_copy((void*)nextsrc, (void*)nextdst, v->type); + nextdst += elem_size; + nextsrc += elem_size; + } + nextdst += (stride - block) * elem_size; + } + } + + /* If members were moved, initialize original array to prevent reuse */ + if(!copy && !v->type->pointerFree) + memset(array, 0, sizeof(elem_size)*arraySize); + + return retval; +} + +UA_StatusCode +UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, + size_t arraySize, const UA_NumericRange range) { + return Variant_setRange(v, array, arraySize, range, false); +} + +UA_StatusCode +UA_Variant_setRangeCopy(UA_Variant *v, const void *array, + size_t arraySize, const UA_NumericRange range) { + return Variant_setRange(v, (void*)(uintptr_t)array, + arraySize, range, true); +} + +/* LocalizedText */ +static void +LocalizedText_deleteMembers(UA_LocalizedText *p, const UA_DataType *_) { + String_deleteMembers(&p->locale, NULL); + String_deleteMembers(&p->text, NULL); +} + +static UA_StatusCode +LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst, + const UA_DataType *_) { + UA_StatusCode retval = UA_String_copy(&src->locale, &dst->locale); + retval |= UA_String_copy(&src->text, &dst->text); + return retval; +} + +/* DataValue */ +static void +DataValue_deleteMembers(UA_DataValue *p, const UA_DataType *_) { + Variant_deletemembers(&p->value, NULL); +} + +static UA_StatusCode +DataValue_copy(UA_DataValue const *src, UA_DataValue *dst, + const UA_DataType *_) { + memcpy(dst, src, sizeof(UA_DataValue)); + UA_Variant_init(&dst->value); + UA_StatusCode retval = Variant_copy(&src->value, &dst->value, NULL); + if(retval != UA_STATUSCODE_GOOD) + DataValue_deleteMembers(dst, NULL); + return retval; +} + +/* DiagnosticInfo */ +static void +DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p, const UA_DataType *_) { + String_deleteMembers(&p->additionalInfo, NULL); + if(p->hasInnerDiagnosticInfo && p->innerDiagnosticInfo) { + DiagnosticInfo_deleteMembers(p->innerDiagnosticInfo, NULL); + UA_free(p->innerDiagnosticInfo); + } +} + +static UA_StatusCode +DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst, + const UA_DataType *_) { + memcpy(dst, src, sizeof(UA_DiagnosticInfo)); + UA_String_init(&dst->additionalInfo); + dst->innerDiagnosticInfo = NULL; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + 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) { + retval |= DiagnosticInfo_copy(src->innerDiagnosticInfo, + dst->innerDiagnosticInfo, NULL); + dst->hasInnerDiagnosticInfo = true; + } else { + dst->hasInnerDiagnosticInfo = false; + retval |= UA_STATUSCODE_BADOUTOFMEMORY; + } + } + return retval; +} + +/********************/ +/* Structured Types */ +/********************/ + +void * +UA_new(const UA_DataType *type) { + void *p = UA_calloc(1, type->memSize); + return p; +} + +static UA_StatusCode +copyByte(const u8 *src, u8 *dst, const UA_DataType *_) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copy2Byte(const u16 *src, u16 *dst, const UA_DataType *_) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copy4Byte(const u32 *src, u32 *dst, const UA_DataType *_) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copy8Byte(const u64 *src, u64 *dst, const UA_DataType *_) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copyGuid(const UA_Guid *src, UA_Guid *dst, const UA_DataType *_) { + *dst = *src; + return UA_STATUSCODE_GOOD; +} + +typedef UA_StatusCode +(*UA_copySignature)(const void *src, void *dst, const UA_DataType *type); + +static const UA_copySignature copyJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = { + (UA_copySignature)copyByte, // Boolean + (UA_copySignature)copyByte, // SByte + (UA_copySignature)copyByte, // Byte + (UA_copySignature)copy2Byte, // Int16 + (UA_copySignature)copy2Byte, // UInt16 + (UA_copySignature)copy4Byte, // Int32 + (UA_copySignature)copy4Byte, // UInt32 + (UA_copySignature)copy8Byte, // Int64 + (UA_copySignature)copy8Byte, // UInt64 + (UA_copySignature)copy4Byte, // Float + (UA_copySignature)copy8Byte, // Double + (UA_copySignature)copy_noInit, // String + (UA_copySignature)copy8Byte, // DateTime + (UA_copySignature)copyGuid, // Guid + (UA_copySignature)copy_noInit, // ByteString + (UA_copySignature)copy_noInit, // XmlElement + (UA_copySignature)NodeId_copy, + (UA_copySignature)ExpandedNodeId_copy, + (UA_copySignature)copy4Byte, // StatusCode + (UA_copySignature)copy_noInit, // QualifiedName + (UA_copySignature)LocalizedText_copy, // LocalizedText + (UA_copySignature)ExtensionObject_copy, + (UA_copySignature)DataValue_copy, + (UA_copySignature)Variant_copy, + (UA_copySignature)DiagnosticInfo_copy, + (UA_copySignature)copy_noInit // all others +}; + +static UA_StatusCode +copy_noInit(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; + u8 membersSize = type->membersSize; + for(size_t i = 0; i < membersSize; ++i) { + const UA_DataTypeMember *m= &type->members[i]; + const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; + const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + if(!m->isArray) { + ptrs += m->padding; + ptrd += m->padding; + size_t fi = mt->builtin ? mt->typeIndex : UA_BUILTIN_TYPES_COUNT; + retval |= copyJumpTable[fi]((const void*)ptrs, (void*)ptrd, mt); + ptrs += mt->memSize; + ptrd += mt->memSize; + } else { + ptrs += m->padding; + ptrd += m->padding; + 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; + ptrs += sizeof(void*); + ptrd += sizeof(void*); + } + } + return retval; +} + +UA_StatusCode +UA_copy(const void *src, void *dst, const UA_DataType *type) { + memset(dst, 0, type->memSize); /* init */ + UA_StatusCode retval = copy_noInit(src, dst, type); + if(retval != UA_STATUSCODE_GOOD) + UA_deleteMembers(dst, type); + return retval; +} + +static void nopDeleteMembers(void *p, const UA_DataType *type) { } + +typedef void (*UA_deleteMembersSignature)(void *p, const UA_DataType *type); + +static const +UA_deleteMembersSignature deleteMembersJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = { + (UA_deleteMembersSignature)nopDeleteMembers, // Boolean + (UA_deleteMembersSignature)nopDeleteMembers, // SByte + (UA_deleteMembersSignature)nopDeleteMembers, // Byte + (UA_deleteMembersSignature)nopDeleteMembers, // Int16 + (UA_deleteMembersSignature)nopDeleteMembers, // UInt16 + (UA_deleteMembersSignature)nopDeleteMembers, // Int32 + (UA_deleteMembersSignature)nopDeleteMembers, // UInt32 + (UA_deleteMembersSignature)nopDeleteMembers, // Int64 + (UA_deleteMembersSignature)nopDeleteMembers, // UInt64 + (UA_deleteMembersSignature)nopDeleteMembers, // Float + (UA_deleteMembersSignature)nopDeleteMembers, // Double + (UA_deleteMembersSignature)String_deleteMembers, // String + (UA_deleteMembersSignature)nopDeleteMembers, // DateTime + (UA_deleteMembersSignature)nopDeleteMembers, // Guid + (UA_deleteMembersSignature)String_deleteMembers, // ByteString + (UA_deleteMembersSignature)String_deleteMembers, // XmlElement + (UA_deleteMembersSignature)NodeId_deleteMembers, + (UA_deleteMembersSignature)ExpandedNodeId_deleteMembers, // ExpandedNodeId + (UA_deleteMembersSignature)nopDeleteMembers, // StatusCode + (UA_deleteMembersSignature)deleteMembers_noInit, // QualifiedName + (UA_deleteMembersSignature)LocalizedText_deleteMembers, // LocalizedText + (UA_deleteMembersSignature)ExtensionObject_deleteMembers, + (UA_deleteMembersSignature)DataValue_deleteMembers, + (UA_deleteMembersSignature)Variant_deletemembers, + (UA_deleteMembersSignature)DiagnosticInfo_deleteMembers, + (UA_deleteMembersSignature)deleteMembers_noInit, +}; + +static void +deleteMembers_noInit(void *p, const UA_DataType *type) { + uintptr_t ptr = (uintptr_t)p; + u8 membersSize = type->membersSize; + for(size_t i = 0; i < membersSize; ++i) { + const UA_DataTypeMember *m= &type->members[i]; + const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; + const UA_DataType *mt = &typelists[!m->namespaceZero][m->memberTypeIndex]; + if(!m->isArray) { + ptr += m->padding; + size_t fi = mt->builtin ? mt->typeIndex : UA_BUILTIN_TYPES_COUNT; + deleteMembersJumpTable[fi]((void*)ptr, mt); + ptr += mt->memSize; + } else { + ptr += m->padding; + size_t length = *(size_t*)ptr; + ptr += sizeof(size_t); + UA_Array_delete(*(void**)ptr, length, mt); + ptr += sizeof(void*); + } + } +} + +void +UA_deleteMembers(void *p, const UA_DataType *type) { + deleteMembers_noInit(p, type); + memset(p, 0, type->memSize); /* init */ +} + +void +UA_delete(void *p, const UA_DataType *type) { + deleteMembers_noInit(p, type); + UA_free(p); +} + +/******************/ +/* Array Handling */ +/******************/ + +void * +UA_Array_new(size_t size, const UA_DataType *type) { + if(size > UA_INT32_MAX) + return NULL; + if(size == 0) + return UA_EMPTY_ARRAY_SENTINEL; + return UA_calloc(size, type->memSize); +} + +UA_StatusCode +UA_Array_copy(const void *src, size_t size, + void **dst, const UA_DataType *type) { + if(size == 0) { + if(src == NULL) + *dst = NULL; + else + *dst= UA_EMPTY_ARRAY_SENTINEL; + return UA_STATUSCODE_GOOD; + } + + if(!type) + return UA_STATUSCODE_BADINTERNALERROR; + + /* calloc, so we don't have to check retval in every iteration of copying */ + *dst = UA_calloc(size, type->memSize); + if(!*dst) + return UA_STATUSCODE_BADOUTOFMEMORY; + + if(type->pointerFree) { + memcpy(*dst, src, type->memSize * size); + return UA_STATUSCODE_GOOD; + } + + uintptr_t ptrs = (uintptr_t)src; + uintptr_t ptrd = (uintptr_t)*dst; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < size; ++i) { + retval |= UA_copy((void*)ptrs, (void*)ptrd, type); + ptrs += type->memSize; + ptrd += type->memSize; + } + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(*dst, size, type); + *dst = NULL; + } + return retval; +} + +void +UA_Array_delete(void *p, size_t size, const UA_DataType *type) { + if(!type->pointerFree) { + uintptr_t ptr = (uintptr_t)p; + for(size_t i = 0; i < size; ++i) { + UA_deleteMembers((void*)ptr, type); + ptr += type->memSize; + } + } + UA_free((void*)((uintptr_t)p & ~(uintptr_t)UA_EMPTY_ARRAY_SENTINEL)); +} + +UA_Boolean +isDataTypeNumeric(const UA_DataType *type) { + // All data types ids between UA_TYPES_BOOLEAN and UA_TYPES_DOUBLE are numeric + for (int i = UA_TYPES_BOOLEAN; i <= UA_TYPES_DOUBLE; ++i) + if (&UA_TYPES[i] == type) + return true; + return false; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2014-2016 (c) Sten Grüner + * Copyright 2014 (c) Leon Urbas + * Copyright 2015 (c) LEvertz + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) Lorenz Haas + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2017 (c) Henrik Norrman + */ + + +/** + * Type Encoding and Decoding + * -------------------------- + * The following methods contain encoding and decoding functions for the builtin + * 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 . */ + +#define UA_ENCODING_MAX_RECURSION 20 + +typedef struct { + /* Pointers to the current position and the last position in the buffer */ + u8 *pos; + const u8 *end; + + u16 depth; /* How often did we en-/decoding recurse? */ + + size_t customTypesArraySize; + const UA_DataType *customTypesArray; + + UA_exchangeEncodeBuffer exchangeBufferCallback; + void *exchangeBufferCallbackHandle; +} Ctx; + +typedef status (*encodeBinarySignature)(const void *UA_RESTRICT src, const UA_DataType *type, + Ctx *UA_RESTRICT ctx); +typedef status (*decodeBinarySignature)(void *UA_RESTRICT dst, const UA_DataType *type, + Ctx *UA_RESTRICT ctx); +typedef size_t (*calcSizeBinarySignature)(const void *UA_RESTRICT p, const UA_DataType *contenttype); + +#define ENCODE_BINARY(TYPE) static status \ + TYPE##_encodeBinary(const UA_##TYPE *UA_RESTRICT src, const UA_DataType *type, Ctx *UA_RESTRICT ctx) +#define DECODE_BINARY(TYPE) static status \ + TYPE##_decodeBinary(UA_##TYPE *UA_RESTRICT dst, const UA_DataType *type, Ctx *UA_RESTRICT ctx) +#define CALCSIZE_BINARY(TYPE) static size_t \ + TYPE##_calcSizeBinary(const UA_##TYPE *UA_RESTRICT src, const UA_DataType *_) +#define ENCODE_DIRECT(SRC, TYPE) TYPE##_encodeBinary((const UA_##TYPE*)SRC, NULL, ctx) +#define DECODE_DIRECT(DST, TYPE) TYPE##_decodeBinary((UA_##TYPE*)DST, NULL, ctx) + +/* Jumptables for de-/encoding and computing the buffer length. The methods in + * the decoding jumptable do not all clean up their allocated memory when an + * error occurs. So a final _deleteMembers needs to be called before returning + * to the user. */ +extern const encodeBinarySignature encodeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1]; +extern const decodeBinarySignature decodeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1]; +extern const calcSizeBinarySignature calcSizeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1]; +static status encodeBinaryInternal(const void *src, const UA_DataType *type, Ctx *ctx); +static status decodeBinaryInternal(void *dst, const UA_DataType *type, Ctx *ctx); + +/** + * Chunking + * ^^^^^^^^ + * Breaking a message 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. + * + * In encodeBinaryInternal and Array_encodeBinary, we store a pointer to the + * last "good position" in the buffer. If we reach the end of the buffer, the + * encoding until that point is sent out. Afterwards the "good position" pointer + * is no longer valid. In order to prevent reuse, no method must return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED after having called exchangeBuffer(). + * This needs to be ensured for the following methods: + * + * encodeBinaryInternal + * Array_encodeBinary + * NodeId_encodeBinary + * ExpandedNodeId_encodeBinary + * LocalizedText_encodeBinary + * ExtensionObject_encodeBinary + * Variant_encodeBinary + * DataValue_encodeBinary + * DiagnosticInfo_encodeBinary */ + +/* Send the current chunk and replace the buffer */ +static status exchangeBuffer(Ctx *ctx) { + if(!ctx->exchangeBufferCallback) + return UA_STATUSCODE_BADENCODINGERROR; + return ctx->exchangeBufferCallback(ctx->exchangeBufferCallbackHandle, &ctx->pos, &ctx->end); +} + +/* If encoding fails, exchange the buffer and try again. It is assumed that the + * following encoding never fails on a fresh buffer. This is true for numerical + * types. */ +static status +encodeWithExchangeBuffer(const void *ptr, encodeBinarySignature encodeFunc, Ctx *ctx) { + status ret = encodeFunc(ptr, NULL, ctx); + if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) { + ret = exchangeBuffer(ctx); + if(ret != UA_STATUSCODE_GOOD) + return ret; + ret = encodeFunc(ptr, NULL, ctx); + } + return ret; +} + +#define ENCODE_WITHEXCHANGE(VAR, TYPE) \ + encodeWithExchangeBuffer((const void*)VAR, (encodeBinarySignature)TYPE##_encodeBinary, ctx) + +/*****************/ +/* Integer Types */ +/*****************/ + +#if !UA_BINARY_OVERLAYABLE_INTEGER + +#pragma message "Integer endianness could not be detected to be little endian. Use slow generic encoding." + +/* These en/decoding functions are only used when the architecture isn't little-endian. */ +static void +UA_encode16(const u16 v, u8 buf[2]) { + buf[0] = (u8)v; + buf[1] = (u8)(v >> 8); +} + +static void +UA_decode16(const u8 buf[2], u16 *v) { + *v = (u16)((u16)buf[0] + (((u16)buf[1]) << 8)); +} + +static void +UA_encode32(const u32 v, u8 buf[4]) { + buf[0] = (u8)v; + buf[1] = (u8)(v >> 8); + buf[2] = (u8)(v >> 16); + buf[3] = (u8)(v >> 24); +} + +static void +UA_decode32(const u8 buf[4], u32 *v) { + *v = (u32)((u32)buf[0] + (((u32)buf[1]) << 8) + + (((u32)buf[2]) << 16) + (((u32)buf[3]) << 24)); +} + +static void +UA_encode64(const u64 v, u8 buf[8]) { + buf[0] = (u8)v; + buf[1] = (u8)(v >> 8); + buf[2] = (u8)(v >> 16); + buf[3] = (u8)(v >> 24); + buf[4] = (u8)(v >> 32); + buf[5] = (u8)(v >> 40); + buf[6] = (u8)(v >> 48); + buf[7] = (u8)(v >> 56); +} + +static void +UA_decode64(const u8 buf[8], u64 *v) { + *v = (u64)((u64)buf[0] + (((u64)buf[1]) << 8) + + (((u64)buf[2]) << 16) + (((u64)buf[3]) << 24) + + (((u64)buf[4]) << 32) + (((u64)buf[5]) << 40) + + (((u64)buf[6]) << 48) + (((u64)buf[7]) << 56)); +} + +#endif /* !UA_BINARY_OVERLAYABLE_INTEGER */ + +/* Boolean */ +ENCODE_BINARY(Boolean) { + if(ctx->pos + sizeof(bool) > ctx->end) + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; + *ctx->pos = *(const u8*)src; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +DECODE_BINARY(Boolean) { + if(ctx->pos + sizeof(bool) > ctx->end) + return UA_STATUSCODE_BADDECODINGERROR; + *dst = (*ctx->pos > 0) ? true : false; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +/* Byte */ +ENCODE_BINARY(Byte) { + if(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; + *dst = *ctx->pos; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +/* UInt16 */ +ENCODE_BINARY(UInt16) { + if(ctx->pos + sizeof(u16) > ctx->end) + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; +#if UA_BINARY_OVERLAYABLE_INTEGER + memcpy(ctx->pos, src, sizeof(u16)); +#else + UA_encode16(*src, ctx->pos); +#endif + ctx->pos += 2; + return UA_STATUSCODE_GOOD; +} + +DECODE_BINARY(UInt16) { + if(ctx->pos + sizeof(u16) > ctx->end) + return UA_STATUSCODE_BADDECODINGERROR; +#if UA_BINARY_OVERLAYABLE_INTEGER + memcpy(dst, ctx->pos, sizeof(u16)); +#else + UA_decode16(ctx->pos, dst); +#endif + ctx->pos += 2; + return UA_STATUSCODE_GOOD; +} + +/* UInt32 */ +ENCODE_BINARY(UInt32) { + if(ctx->pos + sizeof(u32) > ctx->end) + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; +#if UA_BINARY_OVERLAYABLE_INTEGER + memcpy(ctx->pos, src, sizeof(u32)); +#else + UA_encode32(*src, ctx->pos); +#endif + ctx->pos += 4; + return UA_STATUSCODE_GOOD; +} + +DECODE_BINARY(UInt32) { + if(ctx->pos + sizeof(u32) > ctx->end) + return UA_STATUSCODE_BADDECODINGERROR; +#if UA_BINARY_OVERLAYABLE_INTEGER + memcpy(dst, ctx->pos, sizeof(u32)); +#else + UA_decode32(ctx->pos, dst); +#endif + ctx->pos += 4; + return UA_STATUSCODE_GOOD; +} + +/* UInt64 */ +ENCODE_BINARY(UInt64) { + if(ctx->pos + sizeof(u64) > ctx->end) + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; +#if UA_BINARY_OVERLAYABLE_INTEGER + memcpy(ctx->pos, src, sizeof(u64)); +#else + UA_encode64(*src, ctx->pos); +#endif + ctx->pos += 8; + return UA_STATUSCODE_GOOD; +} + +DECODE_BINARY(UInt64) { + if(ctx->pos + sizeof(u64) > ctx->end) + return UA_STATUSCODE_BADDECODINGERROR; +#if UA_BINARY_OVERLAYABLE_INTEGER + memcpy(dst, ctx->pos, sizeof(u64)); +#else + UA_decode64(ctx->pos, dst); +#endif + ctx->pos += 8; + return UA_STATUSCODE_GOOD; +} + +/************************/ +/* Floating Point Types */ +/************************/ + +#if UA_BINARY_OVERLAYABLE_FLOAT +# define Float_encodeBinary UInt32_encodeBinary +# define Float_decodeBinary UInt32_decodeBinary +# define Double_encodeBinary UInt64_encodeBinary +# define Double_decodeBinary UInt64_decodeBinary +#else + +#include <math.h> + +#pragma message "No native IEEE 754 format detected. Use slow generic encoding." + +/* Handling of IEEE754 floating point values was taken from Beej's Guide to + * Network Programming (http://beej.us/guide/bgnet/) and enhanced to cover the + * edge cases +/-0, +/-inf and nan. */ +static uint64_t +pack754(long double f, unsigned bits, unsigned expbits) { + unsigned significandbits = bits - expbits - 1; + long double fnorm; + long long sign; + if(f < 0) { sign = 1; fnorm = -f; } + else { sign = 0; fnorm = f; } + int shift = 0; + while(fnorm >= 2.0) { fnorm /= 2.0; ++shift; } + while(fnorm < 1.0) { fnorm *= 2.0; --shift; } + fnorm = fnorm - 1.0; + long long significand = (long long)(fnorm * ((float)(1LL<<significandbits) + 0.5f)); + long long exponent = shift + ((1<<(expbits-1)) - 1); + return (uint64_t)((sign<<(bits-1)) | (exponent<<(bits-expbits-1)) | significand); +} + +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 += 1.0f; + unsigned bias = (unsigned)(1<<(expbits-1)) - 1; + long long shift = (long long)((i>>significandbits) & (uint64_t)((1LL<<expbits)-1)) - bias; + while(shift > 0) { result *= 2.0; --shift; } + while(shift < 0) { result /= 2.0; ++shift; } + result *= ((i>>(bits-1))&1)? -1.0: 1.0; + return result; +} + +/* Float */ +#define FLOAT_NAN 0xffc00000 +#define FLOAT_INF 0x7f800000 +#define FLOAT_NEG_INF 0xff800000 +#define FLOAT_NEG_ZERO 0x80000000 + +ENCODE_BINARY(Float) { + UA_Float f = *src; + u32 encoded; + /* cppcheck-suppress duplicateExpression */ + if(f != f) encoded = FLOAT_NAN; + else if(f == 0.0f) encoded = signbit(f) ? FLOAT_NEG_ZERO : 0; + else if(f/f != f/f) encoded = f > 0 ? FLOAT_INF : FLOAT_NEG_INF; + else encoded = (u32)pack754(f, 32, 8); + return ENCODE_DIRECT(&encoded, UInt32); +} + +DECODE_BINARY(Float) { + u32 decoded; + status ret = DECODE_DIRECT(&decoded, UInt32); + if(ret != UA_STATUSCODE_GOOD) + return ret; + if(decoded == 0) *dst = 0.0f; + else if(decoded == FLOAT_NEG_ZERO) *dst = -0.0f; + else if(decoded == FLOAT_INF) *dst = INFINITY; + else if(decoded == FLOAT_NEG_INF) *dst = -INFINITY; + else if((decoded >= 0x7f800001 && decoded <= 0x7fffffff) || + (decoded >= 0xff800001)) *dst = NAN; + else *dst = (UA_Float)unpack754(decoded, 32, 8); + return UA_STATUSCODE_GOOD; +} + +/* Double */ +#define DOUBLE_NAN 0xfff8000000000000L +#define DOUBLE_INF 0x7ff0000000000000L +#define DOUBLE_NEG_INF 0xfff0000000000000L +#define DOUBLE_NEG_ZERO 0x8000000000000000L + +ENCODE_BINARY(Double) { + UA_Double d = *src; + u64 encoded; + /* cppcheck-suppress duplicateExpression */ + if(d != d) encoded = DOUBLE_NAN; + else if(d == 0.0) encoded = signbit(d) ? DOUBLE_NEG_ZERO : 0; + else if(d/d != d/d) encoded = d > 0 ? DOUBLE_INF : DOUBLE_NEG_INF; + else encoded = pack754(d, 64, 11); + return ENCODE_DIRECT(&encoded, UInt64); +} + +DECODE_BINARY(Double) { + u64 decoded; + status ret = DECODE_DIRECT(&decoded, UInt64); + if(ret != UA_STATUSCODE_GOOD) + return ret; + if(decoded == 0) *dst = 0.0; + else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0; + else if(decoded == DOUBLE_INF) *dst = INFINITY; + else if(decoded == DOUBLE_NEG_INF) *dst = -INFINITY; + else if((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) || + (decoded >= 0xfff0000000000001L)) *dst = NAN; + else *dst = (UA_Double)unpack754(decoded, 64, 11); + return UA_STATUSCODE_GOOD; +} + +#endif + +/******************/ +/* Array Handling */ +/******************/ + +static status +Array_encodeBinaryOverlayable(uintptr_t ptr, size_t length, size_t elementMemSize, Ctx *ctx) { + /* Store the number of already encoded elements */ + size_t finished = 0; + + /* Loop as long as more elements remain than fit into the chunk */ + while(ctx->end < ctx->pos + (elementMemSize * (length-finished))) { + size_t possible = ((uintptr_t)ctx->end - (uintptr_t)ctx->pos) / (sizeof(u8) * elementMemSize); + size_t possibleMem = possible * elementMemSize; + memcpy(ctx->pos, (void*)ptr, possibleMem); + ctx->pos += possibleMem; + ptr += possibleMem; + finished += possible; + status ret = exchangeBuffer(ctx); + if(ret != UA_STATUSCODE_GOOD) + return ret; + } + + /* Encode the remaining elements */ + memcpy(ctx->pos, (void*)ptr, elementMemSize * (length-finished)); + ctx->pos += elementMemSize * (length-finished); + return UA_STATUSCODE_GOOD; +} + +static status +Array_encodeBinaryComplex(uintptr_t ptr, size_t length, const UA_DataType *type, Ctx *ctx) { + /* Get the encoding function for the data type. The jumptable at + * UA_BUILTIN_TYPES_COUNT points to the generic UA_encodeBinary method */ + size_t encode_index = type->builtin ? type->typeIndex : UA_BUILTIN_TYPES_COUNT; + encodeBinarySignature encodeType = encodeBinaryJumpTable[encode_index]; + + /* Encode every element */ + for(size_t i = 0; i < length; ++i) { + u8 *oldpos = ctx->pos; + status ret = encodeType((const void*)ptr, type, ctx); + ptr += type->memSize; + /* Encoding failed, switch to the next chunk when possible */ + if(ret != UA_STATUSCODE_GOOD) { + if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) { + ctx->pos = oldpos; /* Set buffer position to the end of the last encoded element */ + ret = exchangeBuffer(ctx); + ptr -= type->memSize; /* Undo to retry encoding the ith element */ + --i; + } + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + if(ret != UA_STATUSCODE_GOOD) + return ret; /* Unrecoverable fail */ + } + } + return UA_STATUSCODE_GOOD; +} + +static status +Array_encodeBinary(const void *src, size_t length, const UA_DataType *type, Ctx *ctx) { + /* Check and convert the array length to int32 */ + i32 signed_length = -1; + if(length > UA_INT32_MAX) + return UA_STATUSCODE_BADINTERNALERROR; + if(length > 0) + signed_length = (i32)length; + else if(src == UA_EMPTY_ARRAY_SENTINEL) + signed_length = 0; + + /* Encode the array length */ + status ret = ENCODE_WITHEXCHANGE(&signed_length, UInt32); + + /* Quit early? */ + if(ret != UA_STATUSCODE_GOOD || length == 0) + return ret; + + /* Encode the content */ + if(!type->overlayable) + return Array_encodeBinaryComplex((uintptr_t)src, length, type, ctx); + return Array_encodeBinaryOverlayable((uintptr_t)src, length, type->memSize, ctx); +} + +static status +Array_decodeBinary(void *UA_RESTRICT *UA_RESTRICT dst, size_t *out_length, + const UA_DataType *type, Ctx *ctx) { + /* Decode the length */ + i32 signed_length; + status ret = DECODE_DIRECT(&signed_length, UInt32); /* Int32 */ + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Return early for empty arrays */ + if(signed_length <= 0) { + *out_length = 0; + if(signed_length < 0) + *dst = NULL; + else + *dst = UA_EMPTY_ARRAY_SENTINEL; + return UA_STATUSCODE_GOOD; + } + + /* Filter out arrays that can obviously not be decoded, because the message + * 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; + + /* Allocate memory */ + *dst = UA_calloc(length, type->memSize); + if(!*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; + } + memcpy(*dst, ctx->pos, type->memSize * length); + ctx->pos += type->memSize * length; + } else { + /* Decode array members */ + uintptr_t ptr = (uintptr_t)*dst; + size_t decode_index = type->builtin ? type->typeIndex : UA_BUILTIN_TYPES_COUNT; + for(size_t i = 0; i < length; ++i) { + ret = decodeBinaryJumpTable[decode_index]((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; + } + ptr += type->memSize; + } + } + *out_length = length; + return UA_STATUSCODE_GOOD; +} + +/*****************/ +/* Builtin Types */ +/*****************/ + +ENCODE_BINARY(String) { + return Array_encodeBinary(src->data, src->length, &UA_TYPES[UA_TYPES_BYTE], ctx); +} + +DECODE_BINARY(String) { + return Array_decodeBinary((void**)&dst->data, &dst->length, &UA_TYPES[UA_TYPES_BYTE], ctx); +} + +/* Guid */ +ENCODE_BINARY(Guid) { + status ret = UA_STATUSCODE_GOOD; + 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; + memcpy(ctx->pos, src->data4, 8*sizeof(u8)); + ctx->pos += 8; + return ret; +} + +DECODE_BINARY(Guid) { + status ret = UA_STATUSCODE_GOOD; + 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; + memcpy(dst->data4, ctx->pos, 8*sizeof(u8)); + ctx->pos += 8; + return ret; +} + +/* NodeId */ +#define UA_NODEIDTYPE_NUMERIC_TWOBYTE 0 +#define UA_NODEIDTYPE_NUMERIC_FOURBYTE 1 +#define UA_NODEIDTYPE_NUMERIC_COMPLETE 2 + +#define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40 +#define UA_EXPANDEDNODEID_NAMESPACEURI_FLAG 0x80 + +/* For ExpandedNodeId, we prefill the encoding mask. We can return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED before encoding the string, as the + * buffer is not replaced. */ +static status +NodeId_encodeBinaryWithEncodingMask(UA_NodeId const *src, u8 encoding, Ctx *ctx) { + status ret = UA_STATUSCODE_GOOD; + switch(src->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + if(src->identifier.numeric > UA_UINT16_MAX || src->namespaceIndex > UA_BYTE_MAX) { + encoding |= UA_NODEIDTYPE_NUMERIC_COMPLETE; + ret |= ENCODE_DIRECT(&encoding, Byte); + ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); + ret |= ENCODE_DIRECT(&src->identifier.numeric, UInt32); + } else if(src->identifier.numeric > UA_BYTE_MAX || src->namespaceIndex > 0) { + encoding |= UA_NODEIDTYPE_NUMERIC_FOURBYTE; + ret |= ENCODE_DIRECT(&encoding, Byte); + u8 nsindex = (u8)src->namespaceIndex; + ret |= ENCODE_DIRECT(&nsindex, Byte); + u16 identifier16 = (u16)src->identifier.numeric; + ret |= ENCODE_DIRECT(&identifier16, UInt16); + } else { + encoding |= UA_NODEIDTYPE_NUMERIC_TWOBYTE; + ret |= ENCODE_DIRECT(&encoding, Byte); + u8 identifier8 = (u8)src->identifier.numeric; + ret |= ENCODE_DIRECT(&identifier8, Byte); + } + break; + case UA_NODEIDTYPE_STRING: + encoding |= UA_NODEIDTYPE_STRING; + ret |= ENCODE_DIRECT(&encoding, Byte); + ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); + if(ret != UA_STATUSCODE_GOOD) + return ret; + ret = ENCODE_DIRECT(&src->identifier.string, String); + break; + case UA_NODEIDTYPE_GUID: + encoding |= UA_NODEIDTYPE_GUID; + ret |= ENCODE_DIRECT(&encoding, Byte); + ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); + ret |= ENCODE_DIRECT(&src->identifier.guid, Guid); + break; + case UA_NODEIDTYPE_BYTESTRING: + encoding |= UA_NODEIDTYPE_BYTESTRING; + ret |= ENCODE_DIRECT(&encoding, Byte); + ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); + if(ret != UA_STATUSCODE_GOOD) + return ret; + ret = ENCODE_DIRECT(&src->identifier.byteString, String); /* ByteString */ + break; + default: + return UA_STATUSCODE_BADINTERNALERROR; + } + return ret; +} + +ENCODE_BINARY(NodeId) { + return NodeId_encodeBinaryWithEncodingMask(src, 0, ctx); +} + +DECODE_BINARY(NodeId) { + u8 dstByte = 0, encodingByte = 0; + u16 dstUInt16 = 0; + + /* Decode the encoding bitfield */ + status ret = DECODE_DIRECT(&encodingByte, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Filter out the bits used only for ExpandedNodeIds */ + encodingByte &= (u8)~(UA_EXPANDEDNODEID_SERVERINDEX_FLAG | + UA_EXPANDEDNODEID_NAMESPACEURI_FLAG); + + /* Decode the namespace and identifier */ + switch(encodingByte) { + case UA_NODEIDTYPE_NUMERIC_TWOBYTE: + dst->identifierType = UA_NODEIDTYPE_NUMERIC; + ret = DECODE_DIRECT(&dstByte, Byte); + dst->identifier.numeric = dstByte; + dst->namespaceIndex = 0; + break; + case UA_NODEIDTYPE_NUMERIC_FOURBYTE: + dst->identifierType = UA_NODEIDTYPE_NUMERIC; + ret |= DECODE_DIRECT(&dstByte, Byte); + dst->namespaceIndex = dstByte; + ret |= DECODE_DIRECT(&dstUInt16, UInt16); + dst->identifier.numeric = dstUInt16; + break; + case UA_NODEIDTYPE_NUMERIC_COMPLETE: + dst->identifierType = UA_NODEIDTYPE_NUMERIC; + ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16); + ret |= DECODE_DIRECT(&dst->identifier.numeric, UInt32); + break; + case UA_NODEIDTYPE_STRING: + dst->identifierType = UA_NODEIDTYPE_STRING; + ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16); + ret |= DECODE_DIRECT(&dst->identifier.string, String); + break; + case UA_NODEIDTYPE_GUID: + dst->identifierType = UA_NODEIDTYPE_GUID; + ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16); + ret |= DECODE_DIRECT(&dst->identifier.guid, Guid); + break; + case UA_NODEIDTYPE_BYTESTRING: + dst->identifierType = UA_NODEIDTYPE_BYTESTRING; + ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16); + ret |= DECODE_DIRECT(&dst->identifier.byteString, String); /* ByteString */ + break; + default: + ret |= UA_STATUSCODE_BADINTERNALERROR; + break; + } + return ret; +} + +/* ExpandedNodeId */ +ENCODE_BINARY(ExpandedNodeId) { + /* Set up the encoding mask */ + u8 encoding = 0; + if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL) + encoding |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG; + if(src->serverIndex > 0) + encoding |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG; + + /* Encode the NodeId */ + status ret = NodeId_encodeBinaryWithEncodingMask(&src->nodeId, encoding, ctx); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Encode the namespace. Do not return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED afterwards. */ + 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; + } + + /* Encode the serverIndex */ + if(src->serverIndex > 0) + ret = ENCODE_WITHEXCHANGE(&src->serverIndex, UInt32); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +DECODE_BINARY(ExpandedNodeId) { + /* Decode the encoding mask */ + if(ctx->pos >= ctx->end) + return UA_STATUSCODE_BADDECODINGERROR; + u8 encoding = *ctx->pos; + + /* Decode the NodeId */ + status ret = DECODE_DIRECT(&dst->nodeId, NodeId); + + /* Decode the NamespaceUri */ + if(encoding & UA_EXPANDEDNODEID_NAMESPACEURI_FLAG) { + dst->nodeId.namespaceIndex = 0; + ret |= DECODE_DIRECT(&dst->namespaceUri, String); + } + + /* Decode the ServerIndex */ + if(encoding & UA_EXPANDEDNODEID_SERVERINDEX_FLAG) + ret |= DECODE_DIRECT(&dst->serverIndex, UInt32); + return ret; +} + +/* LocalizedText */ +#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE 0x01 +#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT 0x02 + +ENCODE_BINARY(LocalizedText) { + /* Set up the encoding mask */ + u8 encoding = 0; + if(src->locale.data) + encoding |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE; + if(src->text.data) + encoding |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; + + /* Encode the encoding byte */ + status ret = ENCODE_DIRECT(&encoding, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Encode the strings */ + if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE) + ret |= ENCODE_DIRECT(&src->locale, String); + if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT) + ret |= ENCODE_DIRECT(&src->text, String); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +DECODE_BINARY(LocalizedText) { + /* Decode the encoding mask */ + u8 encoding = 0; + status ret = DECODE_DIRECT(&encoding, Byte); + + /* Decode the content */ + if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE) + ret |= DECODE_DIRECT(&dst->locale, String); + if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT) + ret |= DECODE_DIRECT(&dst->text, String); + return ret; +} + +/* The binary encoding has a different nodeid from the data type. So it is not + * 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]; + } + + /* When other namespace look in custom types, too */ + if(typeId->namespaceIndex != 0) { + for(size_t i = 0; i < ctx->customTypesArraySize; ++i) { + if(ctx->customTypesArray[i].binaryEncodingId == typeId->identifier.numeric && + ctx->customTypesArray[i].typeId.namespaceIndex == typeId->namespaceIndex) + return &ctx->customTypesArray[i]; + } + } + + return NULL; +} + +const UA_DataType * +UA_findDataTypeByBinary(const UA_NodeId *typeId) { + Ctx ctx; + ctx.customTypesArraySize = 0; + ctx.customTypesArray = NULL; + return UA_findDataTypeByBinaryInternal(typeId, &ctx); +} + +/* ExtensionObject */ +ENCODE_BINARY(ExtensionObject) { + u8 encoding = (u8)src->encoding; + + /* No content or already encoded content. Do not return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED after encoding the NodeId. */ + if(encoding <= UA_EXTENSIONOBJECT_ENCODED_XML) { + status ret = ENCODE_DIRECT(&src->content.encoded.typeId, NodeId); + if(ret != UA_STATUSCODE_GOOD) + return ret; + ret = ENCODE_WITHEXCHANGE(&encoding, Byte); + if(ret != UA_STATUSCODE_GOOD) + 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 */ + break; + default: + ret = UA_STATUSCODE_BADINTERNALERROR; + } + return ret; + } + + /* Cannot encode with no data or no type description */ + 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); + + /* Write the encoding byte */ + encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; + ret |= ENCODE_DIRECT(&encoding, Byte); + + /* Compute the content length */ + const UA_DataType *contentType = src->content.decoded.type; + size_t len = UA_calcSizeBinary(src->content.decoded.data, contentType); + + /* Encode the content length */ + if(len > UA_INT32_MAX) + return UA_STATUSCODE_BADENCODINGERROR; + i32 signed_len = (i32)len; + ret |= ENCODE_DIRECT(&signed_len, UInt32); /* Int32 */ + + /* Return early upon failures (no buffer exchange until here) */ + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Encode the content */ + return encodeBinaryInternal(src->content.decoded.data, contentType, ctx); +} + +static status +ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *typeId, Ctx *ctx) { + /* Lookup the datatype */ + const UA_DataType *type = UA_findDataTypeByBinaryInternal(typeId, ctx); + + /* Unknown type, just take the binary content */ + if(!type) { + dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; + UA_NodeId_copy(typeId, &dst->content.encoded.typeId); + return DECODE_DIRECT(&dst->content.encoded.body, String); /* ByteString */ + } + + /* Allocate memory */ + dst->content.decoded.data = UA_new(type); + if(!dst->content.decoded.data) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Jump over the length field (TODO: check if the decoded length matches) */ + ctx->pos += 4; + + /* Decode */ + dst->encoding = UA_EXTENSIONOBJECT_DECODED; + dst->content.decoded.type = type; + size_t decode_index = type->builtin ? type->typeIndex : UA_BUILTIN_TYPES_COUNT; + return decodeBinaryJumpTable[decode_index](dst->content.decoded.data, type, ctx); +} + +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_init(&binTypeId); + status ret = UA_STATUSCODE_GOOD; + ret |= DECODE_DIRECT(&binTypeId, NodeId); + ret |= DECODE_DIRECT(&encoding, Byte); + if(ret != UA_STATUSCODE_GOOD) { + UA_NodeId_deleteMembers(&binTypeId); + return ret; + } + + if(encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) { + ret = ExtensionObject_decodeBinaryContent(dst, &binTypeId, ctx); + UA_NodeId_deleteMembers(&binTypeId); + } else if(encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { + dst->encoding = (UA_ExtensionObjectEncoding)encoding; + dst->content.encoded.typeId = binTypeId; /* move to dst */ + dst->content.encoded.body = UA_BYTESTRING_NULL; + } else if(encoding == UA_EXTENSIONOBJECT_ENCODED_XML) { + 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_deleteMembers(&dst->content.encoded.typeId); + } else { + UA_NodeId_deleteMembers(&binTypeId); + ret = UA_STATUSCODE_BADDECODINGERROR; + } + + return ret; +} + +/* Variant */ + +/* Never returns UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED */ +static status +Variant_encodeBinaryWrapExtensionObject(const UA_Variant *src, const bool isArray, Ctx *ctx) { + /* Default to 1 for a scalar. */ + size_t length = 1; + + /* Encode the array length if required */ + status ret = UA_STATUSCODE_GOOD; + if(isArray) { + if(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; + } + + /* Set up the ExtensionObject */ + UA_ExtensionObject eo; + UA_ExtensionObject_init(&eo); + eo.encoding = UA_EXTENSIONOBJECT_DECODED; + eo.content.decoded.type = src->type; + const u16 memSize = src->type->memSize; + uintptr_t ptr = (uintptr_t)src->data; + + /* Iterate over the array */ + for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) { + eo.content.decoded.data = (void*)ptr; + ret = encodeBinaryInternal(&eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], ctx); + ptr += memSize; + } + return ret; +} + +enum UA_VARIANT_ENCODINGMASKTYPE { + UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F, /* bits 0:5 */ + UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS = (0x01 << 6), /* bit 6 */ + UA_VARIANT_ENCODINGMASKTYPE_ARRAY = (0x01 << 7) /* bit 7 */ +}; + + + +ENCODE_BINARY(Variant) { + /* Quit early for the empty variant */ + u8 encoding = 0; + if(!src->type) + return ENCODE_DIRECT(&encoding, Byte); + + /* Set the content type in the encoding mask */ + const bool isBuiltin = src->type->builtin; + const bool isAlias = src->type->membersSize == 1 + && UA_TYPES[src->type->members[0].memberTypeIndex].builtin; + if(isBuiltin) + encoding |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(src->type->typeIndex + 1); + else if(isAlias) + encoding |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(src->type->members[0].memberTypeIndex + 1); + else + encoding |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_EXTENSIONOBJECT + 1); + + /* Set the array type in the encoding mask */ + const bool isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL; + const bool hasDimensions = isArray && src->arrayDimensionsSize > 0; + if(isArray) { + encoding |= UA_VARIANT_ENCODINGMASKTYPE_ARRAY; + if(hasDimensions) + encoding |= UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS; + } + + /* Encode the encoding byte */ + status ret = ENCODE_DIRECT(&encoding, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Encode the content */ + if(!isBuiltin && !isAlias) + ret = Variant_encodeBinaryWrapExtensionObject(src, isArray, ctx); + else if(!isArray) + ret = encodeBinaryInternal(src->data, src->type, ctx); + else + ret = Array_encodeBinary(src->data, src->arrayLength, src->type, ctx); + + /* Encode the array dimensions */ + if(hasDimensions && ret == UA_STATUSCODE_GOOD) + ret = Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_INT32], ctx); + return ret; +} + +static status +Variant_decodeBinaryUnwrapExtensionObject(UA_Variant *dst, Ctx *ctx) { + /* Save the position in the ByteString. If unwrapping is not possible, start + * from here to decode a normal ExtensionObject. */ + u8 *old_pos = ctx->pos; + + /* Decode the DataType */ + UA_NodeId typeId; + UA_NodeId_init(&typeId); + status ret = DECODE_DIRECT(&typeId, NodeId); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Decode the EncodingByte */ + u8 encoding; + ret = DECODE_DIRECT(&encoding, Byte); + if(ret != UA_STATUSCODE_GOOD) { + UA_NodeId_deleteMembers(&typeId); + return ret; + } + + /* Search for the datatype. Default to ExtensionObject. */ + if(encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING && + (dst->type = UA_findDataTypeByBinaryInternal(&typeId, ctx)) != NULL) { + /* Jump over the length field (TODO: check if length matches) */ + ctx->pos += 4; + } else { + /* Reset and decode as ExtensionObject */ + dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]; + ctx->pos = old_pos; + UA_NodeId_deleteMembers(&typeId); + } + + /* Allocate memory */ + dst->data = UA_new(dst->type); + if(!dst->data) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Decode the content */ + size_t decode_index = dst->type->builtin ? dst->type->typeIndex : UA_BUILTIN_TYPES_COUNT; + return decodeBinaryJumpTable[decode_index](dst->data, dst->type, ctx); +} + +/* The resulting variant always has the storagetype UA_VARIANT_DATA. */ +DECODE_BINARY(Variant) { + /* Decode the encoding byte */ + u8 encodingByte; + status ret = DECODE_DIRECT(&encodingByte, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Return early for an empty variant (was already _inited) */ + if(encodingByte == 0) + return UA_STATUSCODE_GOOD; + + /* Does the variant contain an array? */ + const bool isArray = (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_ARRAY) > 0; + + /* Get the datatype of the content. The type must be a builtin data type. + * All not-builtin types are wrapped in an ExtensionObject. */ + size_t typeIndex = (size_t)((encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1); + if(typeIndex > UA_TYPES_DIAGNOSTICINFO) + return UA_STATUSCODE_BADDECODINGERROR; + + /* A variant cannot contain a variant. But it can contain an array of + * variants */ + if(typeIndex == UA_TYPES_VARIANT && !isArray) + return UA_STATUSCODE_BADDECODINGERROR; + + /* Check the recursion limit */ + if(ctx->depth > UA_ENCODING_MAX_RECURSION) + return UA_STATUSCODE_BADENCODINGERROR; + ctx->depth++; + + /* Decode the content */ + dst->type = &UA_TYPES[typeIndex]; + if(isArray) { + ret = Array_decodeBinary(&dst->data, &dst->arrayLength, dst->type, ctx); + } else if(typeIndex != UA_TYPES_EXTENSIONOBJECT) { + dst->data = UA_new(dst->type); + if(!dst->data) + return UA_STATUSCODE_BADOUTOFMEMORY; + ret = decodeBinaryJumpTable[typeIndex](dst->data, dst->type, ctx); + } else { + ret = Variant_decodeBinaryUnwrapExtensionObject(dst, ctx); + } + + /* Decode array dimensions */ + if(isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS) > 0) + ret |= Array_decodeBinary((void**)&dst->arrayDimensions, &dst->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_INT32], ctx); + + ctx->depth--; + return ret; +} + +/* DataValue */ +ENCODE_BINARY(DataValue) { + /* Set up the encoding mask */ + u8 encodingMask = (u8) + (((u8)src->hasValue) | + ((u8)src->hasStatus << 1) | + ((u8)src->hasSourceTimestamp << 2) | + ((u8)src->hasServerTimestamp << 3) | + ((u8)src->hasSourcePicoseconds << 4) | + ((u8)src->hasServerPicoseconds << 5)); + + /* Encode the encoding byte */ + status ret = ENCODE_DIRECT(&encodingMask, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Encode the variant. Afterwards, do not return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED, as the buffer might have been + * exchanged during encoding of the variant. */ + if(src->hasValue) { + ret = ENCODE_DIRECT(&src->value, Variant); + if(ret != UA_STATUSCODE_GOOD) + return ret; + } + + if(src->hasStatus) + ret |= ENCODE_WITHEXCHANGE(&src->status, UInt32); + if(src->hasSourceTimestamp) + ret |= ENCODE_WITHEXCHANGE(&src->sourceTimestamp, UInt64); + if(src->hasSourcePicoseconds) + ret |= ENCODE_WITHEXCHANGE(&src->sourcePicoseconds, UInt16); + if(src->hasServerTimestamp) + ret |= ENCODE_WITHEXCHANGE(&src->serverTimestamp, UInt64); + if(src->hasServerPicoseconds) + ret |= ENCODE_WITHEXCHANGE(&src->serverPicoseconds, UInt16); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +#define MAX_PICO_SECONDS 9999 + +DECODE_BINARY(DataValue) { + /* Decode the encoding mask */ + u8 encodingMask; + status ret = DECODE_DIRECT(&encodingMask, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Check the recursion limit */ + if(ctx->depth > UA_ENCODING_MAX_RECURSION) + return UA_STATUSCODE_BADENCODINGERROR; + ctx->depth++; + + + /* Decode the content */ + if(encodingMask & 0x01) { + dst->hasValue = true; + ret |= DECODE_DIRECT(&dst->value, Variant); + } + if(encodingMask & 0x02) { + dst->hasStatus = true; + ret |= DECODE_DIRECT(&dst->status, UInt32); /* StatusCode */ + } + if(encodingMask & 0x04) { + dst->hasSourceTimestamp = true; + ret |= DECODE_DIRECT(&dst->sourceTimestamp, UInt64); /* DateTime */ + } + if(encodingMask & 0x10) { + dst->hasSourcePicoseconds = true; + ret |= DECODE_DIRECT(&dst->sourcePicoseconds, UInt16); + if(dst->sourcePicoseconds > MAX_PICO_SECONDS) + dst->sourcePicoseconds = MAX_PICO_SECONDS; + } + if(encodingMask & 0x08) { + dst->hasServerTimestamp = true; + ret |= DECODE_DIRECT(&dst->serverTimestamp, UInt64); /* DateTime */ + } + if(encodingMask & 0x20) { + dst->hasServerPicoseconds = true; + ret |= DECODE_DIRECT(&dst->serverPicoseconds, UInt16); + if(dst->serverPicoseconds > MAX_PICO_SECONDS) + dst->serverPicoseconds = MAX_PICO_SECONDS; + } + + ctx->depth--; + + return ret; +} + +/* DiagnosticInfo */ +ENCODE_BINARY(DiagnosticInfo) { + /* Set up the encoding mask */ + u8 encodingMask = (u8) + ((u8)src->hasSymbolicId | ((u8)src->hasNamespaceUri << 1) | + ((u8)src->hasLocalizedText << 2) | ((u8)src->hasLocale << 3) | + ((u8)src->hasAdditionalInfo << 4) | ((u8)src->hasInnerDiagnosticInfo << 5)); + + /* Encode the numeric content */ + status ret = ENCODE_DIRECT(&encodingMask, Byte); + if(src->hasSymbolicId) + ret |= ENCODE_DIRECT(&src->symbolicId, UInt32); /* Int32 */ + if(src->hasNamespaceUri) + ret |= ENCODE_DIRECT(&src->namespaceUri, UInt32); /* Int32 */ + if(src->hasLocalizedText) + ret |= ENCODE_DIRECT(&src->localizedText, UInt32); /* Int32 */ + if(src->hasLocale) + ret |= ENCODE_DIRECT(&src->locale, UInt32); /* Int32 */ + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Encode the additional info */ + if(src->hasAdditionalInfo) { + ret = ENCODE_DIRECT(&src->additionalInfo, String); + if(ret != UA_STATUSCODE_GOOD) + return ret; + } + + /* From here on, do not return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED, as + * the buffer might have been exchanged during encoding of the string. */ + + /* Encode the inner status code */ + if(src->hasInnerStatusCode) { + ret = ENCODE_WITHEXCHANGE(&src->innerStatusCode, UInt32); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + if(ret != UA_STATUSCODE_GOOD) + return ret; + } + + /* Encode the inner diagnostic info */ + if(src->hasInnerDiagnosticInfo) + ret = encodeBinaryInternal(src->innerDiagnosticInfo, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], ctx); + + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +DECODE_BINARY(DiagnosticInfo) { + /* Decode the encoding mask */ + u8 encodingMask; + status ret = DECODE_DIRECT(&encodingMask, Byte); + if(ret != UA_STATUSCODE_GOOD) + return ret; + + /* Decode the content */ + if(encodingMask & 0x01) { + dst->hasSymbolicId = true; + ret |= DECODE_DIRECT(&dst->symbolicId, UInt32); /* Int32 */ + } + if(encodingMask & 0x02) { + dst->hasNamespaceUri = true; + ret |= DECODE_DIRECT(&dst->namespaceUri, UInt32); /* Int32 */ + } + if(encodingMask & 0x04) { + dst->hasLocalizedText = true; + ret |= DECODE_DIRECT(&dst->localizedText, UInt32); /* Int32 */ + } + if(encodingMask & 0x08) { + dst->hasLocale = true; + ret |= DECODE_DIRECT(&dst->locale, UInt32); /* Int32 */ + } + if(encodingMask & 0x10) { + dst->hasAdditionalInfo = true; + ret |= DECODE_DIRECT(&dst->additionalInfo, String); + } + if(encodingMask & 0x20) { + dst->hasInnerStatusCode = true; + ret |= DECODE_DIRECT(&dst->innerStatusCode, UInt32); /* StatusCode */ + } + if(encodingMask & 0x40) { + /* innerDiagnosticInfo is allocated on the heap */ + dst->innerDiagnosticInfo = (UA_DiagnosticInfo*) + UA_calloc(1, sizeof(UA_DiagnosticInfo)); + if(!dst->innerDiagnosticInfo) + return UA_STATUSCODE_BADOUTOFMEMORY; + dst->hasInnerDiagnosticInfo = true; + + /* Check the recursion limit */ + if(ctx->depth > UA_ENCODING_MAX_RECURSION) + return UA_STATUSCODE_BADENCODINGERROR; + + ctx->depth++; + ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo); + ctx->depth--; + } + return ret; +} + +/********************/ +/* Structured Types */ +/********************/ + +const encodeBinarySignature encodeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = { + (encodeBinarySignature)Boolean_encodeBinary, + (encodeBinarySignature)Byte_encodeBinary, /* SByte */ + (encodeBinarySignature)Byte_encodeBinary, + (encodeBinarySignature)UInt16_encodeBinary, /* Int16 */ + (encodeBinarySignature)UInt16_encodeBinary, + (encodeBinarySignature)UInt32_encodeBinary, /* Int32 */ + (encodeBinarySignature)UInt32_encodeBinary, + (encodeBinarySignature)UInt64_encodeBinary, /* Int64 */ + (encodeBinarySignature)UInt64_encodeBinary, + (encodeBinarySignature)Float_encodeBinary, + (encodeBinarySignature)Double_encodeBinary, + (encodeBinarySignature)String_encodeBinary, + (encodeBinarySignature)UInt64_encodeBinary, /* DateTime */ + (encodeBinarySignature)Guid_encodeBinary, + (encodeBinarySignature)String_encodeBinary, /* ByteString */ + (encodeBinarySignature)String_encodeBinary, /* XmlElement */ + (encodeBinarySignature)NodeId_encodeBinary, + (encodeBinarySignature)ExpandedNodeId_encodeBinary, + (encodeBinarySignature)UInt32_encodeBinary, /* StatusCode */ + (encodeBinarySignature)encodeBinaryInternal, /* QualifiedName */ + (encodeBinarySignature)LocalizedText_encodeBinary, + (encodeBinarySignature)ExtensionObject_encodeBinary, + (encodeBinarySignature)DataValue_encodeBinary, + (encodeBinarySignature)Variant_encodeBinary, + (encodeBinarySignature)DiagnosticInfo_encodeBinary, + (encodeBinarySignature)encodeBinaryInternal, +}; + +static status +encodeBinaryInternal(const void *src, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + if(ctx->depth > UA_ENCODING_MAX_RECURSION) + return UA_STATUSCODE_BADENCODINGERROR; + ctx->depth++; + + uintptr_t ptr = (uintptr_t)src; + status ret = UA_STATUSCODE_GOOD; + u8 membersSize = type->membersSize; + const UA_DataType *typelists[2] = { UA_TYPES, &type[-type->typeIndex] }; + for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) { + const UA_DataTypeMember *member = &type->members[i]; + const UA_DataType *membertype = &typelists[!member->namespaceZero][member->memberTypeIndex]; + if(!member->isArray) { + ptr += member->padding; + size_t encode_index = membertype->builtin ? membertype->typeIndex : UA_BUILTIN_TYPES_COUNT; + size_t memSize = membertype->memSize; + u8 *oldpos = ctx->pos; + ret = encodeBinaryJumpTable[encode_index]((const void*)ptr, membertype, ctx); + ptr += memSize; + if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) { + ctx->pos = oldpos; /* exchange/send the buffer */ + ret = exchangeBuffer(ctx); + ptr -= member->padding + memSize; /* encode the same member in the next iteration */ + if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED || ctx->pos + memSize > ctx->end) { + /* the send buffer is too small to encode the member, even after exchangeBuffer */ + ret = UA_STATUSCODE_BADRESPONSETOOLARGE; + break; + } + --i; + } + } else { + ptr += member->padding; + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, membertype, ctx); + ptr += sizeof(void*); + } + } + + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + ctx->depth--; + return ret; +} + +status +UA_encodeBinary(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; + ctx.end = *bufEnd; + ctx.depth = 0; + ctx.exchangeBufferCallback = exchangeCallback; + ctx.exchangeBufferCallbackHandle = exchangeHandle; + + if (!ctx.pos) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + /* Encode */ + status ret = encodeBinaryInternal(src, type, &ctx); + + /* Set the new buffer position for the output. Beware that the buffer might + * have been exchanged internally. */ + *bufPos = ctx.pos; + *bufEnd = ctx.end; + return ret; +} + +const decodeBinarySignature decodeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = { + (decodeBinarySignature)Boolean_decodeBinary, + (decodeBinarySignature)Byte_decodeBinary, /* SByte */ + (decodeBinarySignature)Byte_decodeBinary, + (decodeBinarySignature)UInt16_decodeBinary, /* Int16 */ + (decodeBinarySignature)UInt16_decodeBinary, + (decodeBinarySignature)UInt32_decodeBinary, /* Int32 */ + (decodeBinarySignature)UInt32_decodeBinary, + (decodeBinarySignature)UInt64_decodeBinary, /* Int64 */ + (decodeBinarySignature)UInt64_decodeBinary, + (decodeBinarySignature)Float_decodeBinary, + (decodeBinarySignature)Double_decodeBinary, + (decodeBinarySignature)String_decodeBinary, + (decodeBinarySignature)UInt64_decodeBinary, /* DateTime */ + (decodeBinarySignature)Guid_decodeBinary, + (decodeBinarySignature)String_decodeBinary, /* ByteString */ + (decodeBinarySignature)String_decodeBinary, /* XmlElement */ + (decodeBinarySignature)NodeId_decodeBinary, + (decodeBinarySignature)ExpandedNodeId_decodeBinary, + (decodeBinarySignature)UInt32_decodeBinary, /* StatusCode */ + (decodeBinarySignature)decodeBinaryInternal, /* QualifiedName */ + (decodeBinarySignature)LocalizedText_decodeBinary, + (decodeBinarySignature)ExtensionObject_decodeBinary, + (decodeBinarySignature)DataValue_decodeBinary, + (decodeBinarySignature)Variant_decodeBinary, + (decodeBinarySignature)DiagnosticInfo_decodeBinary, + (decodeBinarySignature)decodeBinaryInternal +}; + +static status +decodeBinaryInternal(void *dst, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + if(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] }; + for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) { + const UA_DataTypeMember *member = &type->members[i]; + const UA_DataType *membertype = &typelists[!member->namespaceZero][member->memberTypeIndex]; + if(!member->isArray) { + ptr += member->padding; + size_t fi = membertype->builtin ? membertype->typeIndex : UA_BUILTIN_TYPES_COUNT; + size_t memSize = membertype->memSize; + ret |= decodeBinaryJumpTable[fi]((void *UA_RESTRICT)ptr, membertype, ctx); + ptr += memSize; + } else { + ptr += member->padding; + size_t *length = (size_t*)ptr; + ptr += sizeof(size_t); + ret |= Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, membertype, ctx); + ptr += sizeof(void*); + } + } + + ctx->depth--; + return ret; +} + +status +UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, + const UA_DataType *type, size_t customTypesSize, + const UA_DataType *customTypes) { + /* Set up the context */ + Ctx ctx; + ctx.pos = &src->data[*offset]; + ctx.end = &src->data[src->length]; + ctx.depth = 0; + ctx.customTypesArraySize = customTypesSize; + ctx.customTypesArray = customTypes; + + /* Decode */ + memset(dst, 0, type->memSize); /* Initialize the value */ + status ret = decodeBinaryInternal(dst, type, &ctx); + + if(ret == UA_STATUSCODE_GOOD) { + /* Set the new offset */ + *offset = (size_t)(ctx.pos - src->data) / sizeof(u8); + } else { + /* Clean up */ + UA_deleteMembers(dst, type); + memset(dst, 0, type->memSize); + } + return ret; +} + +/** + * Compute the Message Size + * ------------------------ + * The following methods are used to compute the length of a datum in binary + * encoding. */ + +static size_t +Array_calcSizeBinary(const void *src, size_t length, const UA_DataType *type) { + size_t s = 4; /* length */ + if(type->overlayable) { + s += type->memSize * length; + return s; + } + uintptr_t ptr = (uintptr_t)src; + size_t encode_index = type->builtin ? type->typeIndex : UA_BUILTIN_TYPES_COUNT; + for(size_t i = 0; i < length; ++i) { + s += calcSizeBinaryJumpTable[encode_index]((const void*)ptr, type); + ptr += type->memSize; + } + return s; +} + +static size_t +calcSizeBinaryMemSize(const void *UA_RESTRICT p, const UA_DataType *type) { + return type->memSize; +} + +CALCSIZE_BINARY(String) { + return 4 + src->length; +} + +CALCSIZE_BINARY(Guid) { + return 16; +} + +CALCSIZE_BINARY(NodeId) { + size_t s = 1; /* encoding byte */ + switch(src->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + if(src->identifier.numeric > UA_UINT16_MAX || src->namespaceIndex > UA_BYTE_MAX) { + s += 6; + } else if(src->identifier.numeric > UA_BYTE_MAX || src->namespaceIndex > 0) { + s += 3; + } else { + s += 1; + } + break; + case UA_NODEIDTYPE_BYTESTRING: + case UA_NODEIDTYPE_STRING: + s += 2; + s += String_calcSizeBinary(&src->identifier.string, NULL); + break; + case UA_NODEIDTYPE_GUID: + s += 18; + break; + default: + return 0; + } + return s; +} + +CALCSIZE_BINARY(ExpandedNodeId) { + size_t s = NodeId_calcSizeBinary(&src->nodeId, NULL); + if(src->namespaceUri.length > 0) + s += String_calcSizeBinary(&src->namespaceUri, NULL); + if(src->serverIndex > 0) + s += 4; + return s; +} + +CALCSIZE_BINARY(LocalizedText) { + size_t s = 1; /* encoding byte */ + if(src->locale.data) + s += String_calcSizeBinary(&src->locale, NULL); + if(src->text.data) + s += String_calcSizeBinary(&src->text, NULL); + return s; +} + +CALCSIZE_BINARY(ExtensionObject) { + size_t s = 1; /* encoding byte */ + if(src->encoding > UA_EXTENSIONOBJECT_ENCODED_XML) { + if(!src->content.decoded.type || !src->content.decoded.data) + return 0; + if(src->content.decoded.type->typeId.identifierType != UA_NODEIDTYPE_NUMERIC) + return 0; + s += NodeId_calcSizeBinary(&src->content.decoded.type->typeId, NULL); + s += 4; /* length */ + const UA_DataType *type = src->content.decoded.type; + size_t encode_index = type->builtin ? type->typeIndex : UA_BUILTIN_TYPES_COUNT; + s += calcSizeBinaryJumpTable[encode_index](src->content.decoded.data, type); + } else { + s += NodeId_calcSizeBinary(&src->content.encoded.typeId, NULL); + switch(src->encoding) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + break; + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + case UA_EXTENSIONOBJECT_ENCODED_XML: + s += String_calcSizeBinary(&src->content.encoded.body, NULL); + break; + default: + return 0; + } + } + return s; +} + +CALCSIZE_BINARY(Variant) { + size_t s = 1; /* encoding byte */ + if(!src->type) + return s; + + bool isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL; + bool hasDimensions = isArray && src->arrayDimensionsSize > 0; + bool isBuiltin = src->type->builtin; + + + size_t encode_index = src->type->typeIndex; + if(!isBuiltin) { + encode_index = UA_BUILTIN_TYPES_COUNT; + if(src->type->typeId.identifierType != UA_NODEIDTYPE_NUMERIC) + return 0; + } + + uintptr_t ptr = (uintptr_t)src->data; + size_t length = isArray ? src->arrayLength : 1; + if (isArray) + s += Array_calcSizeBinary((const void*)ptr, length, src->type); + else + s += calcSizeBinaryJumpTable[encode_index]((const void*)ptr, src->type); + + if (!isBuiltin) { + /* The type is wrapped inside an extensionobject */ + /* (NodeId + encoding byte + extension object length) * array length */ + s += (NodeId_calcSizeBinary(&src->type->typeId, NULL) + 1 + 4) * length; + } + + if(hasDimensions) + s += Array_calcSizeBinary(src->arrayDimensions, src->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_INT32]); + return s; +} + +CALCSIZE_BINARY(DataValue) { + size_t s = 1; /* encoding byte */ + if(src->hasValue) + s += Variant_calcSizeBinary(&src->value, NULL); + if(src->hasStatus) + s += 4; + if(src->hasSourceTimestamp) + s += 8; + if(src->hasSourcePicoseconds) + s += 2; + if(src->hasServerTimestamp) + s += 8; + if(src->hasServerPicoseconds) + s += 2; + return s; +} + +CALCSIZE_BINARY(DiagnosticInfo) { + size_t s = 1; /* encoding byte */ + if(src->hasSymbolicId) + s += 4; + if(src->hasNamespaceUri) + s += 4; + if(src->hasLocalizedText) + s += 4; + if(src->hasLocale) + s += 4; + if(src->hasAdditionalInfo) + s += String_calcSizeBinary(&src->additionalInfo, NULL); + if(src->hasInnerStatusCode) + s += 4; + if(src->hasInnerDiagnosticInfo) + s += DiagnosticInfo_calcSizeBinary(src->innerDiagnosticInfo, NULL); + return s; +} + +const calcSizeBinarySignature calcSizeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = { + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Boolean */ + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Byte */ + (calcSizeBinarySignature)calcSizeBinaryMemSize, + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Int16 */ + (calcSizeBinarySignature)calcSizeBinaryMemSize, + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Int32 */ + (calcSizeBinarySignature)calcSizeBinaryMemSize, + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Int64 */ + (calcSizeBinarySignature)calcSizeBinaryMemSize, + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Float */ + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* Double */ + (calcSizeBinarySignature)String_calcSizeBinary, + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* DateTime */ + (calcSizeBinarySignature)Guid_calcSizeBinary, + (calcSizeBinarySignature)String_calcSizeBinary, /* ByteString */ + (calcSizeBinarySignature)String_calcSizeBinary, /* XmlElement */ + (calcSizeBinarySignature)NodeId_calcSizeBinary, + (calcSizeBinarySignature)ExpandedNodeId_calcSizeBinary, + (calcSizeBinarySignature)calcSizeBinaryMemSize, /* StatusCode */ + (calcSizeBinarySignature)UA_calcSizeBinary, /* QualifiedName */ + (calcSizeBinarySignature)LocalizedText_calcSizeBinary, + (calcSizeBinarySignature)ExtensionObject_calcSizeBinary, + (calcSizeBinarySignature)DataValue_calcSizeBinary, + (calcSizeBinarySignature)Variant_calcSizeBinary, + (calcSizeBinarySignature)DiagnosticInfo_calcSizeBinary, + (calcSizeBinarySignature)UA_calcSizeBinary +}; + +size_t +UA_calcSizeBinary(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] }; + for(size_t i = 0; i < membersSize; ++i) { + const UA_DataTypeMember *member = &type->members[i]; + const UA_DataType *membertype = &typelists[!member->namespaceZero][member->memberTypeIndex]; + if(!member->isArray) { + ptr += member->padding; + size_t encode_index = membertype->builtin ? membertype->typeIndex : UA_BUILTIN_TYPES_COUNT; + s += calcSizeBinaryJumpTable[encode_index]((const void*)ptr, membertype); + ptr += membertype->memSize; + } else { + ptr += member->padding; + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + s += Array_calcSizeBinary(*(void *UA_RESTRICT const *)ptr, length, membertype); + ptr += sizeof(void*); + } + } + return s; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_types_generated.c" ***********************************/ + +/* Generated from Opc.Ua.Types.bsd with script /home/jvoe/open62541/tools/generate_datatypes.py + * on host rigel by user jvoe at 2019-01-04 01:18:40 */ + + +/* Boolean */ +static UA_DataTypeMember Boolean_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SByte */ +static UA_DataTypeMember SByte_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_SBYTE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Byte */ +static UA_DataTypeMember Byte_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Int16 */ +static UA_DataTypeMember Int16_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT16, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UInt16 */ +static UA_DataTypeMember UInt16_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_UINT16, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Int32 */ +static UA_DataTypeMember Int32_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UInt32 */ +static UA_DataTypeMember UInt32_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Int64 */ +static UA_DataTypeMember Int64_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT64, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UInt64 */ +static UA_DataTypeMember UInt64_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_UINT64, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Float */ +static UA_DataTypeMember Float_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_FLOAT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Double */ +static UA_DataTypeMember Double_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* String */ +static UA_DataTypeMember String_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DateTime */ +static UA_DataTypeMember DateTime_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Guid */ +static UA_DataTypeMember Guid_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_GUID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ByteString */ +static UA_DataTypeMember ByteString_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* XmlElement */ +static UA_DataTypeMember XmlElement_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* NodeId */ +static UA_DataTypeMember NodeId_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ExpandedNodeId */ +static UA_DataTypeMember ExpandedNodeId_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* StatusCode */ +static UA_DataTypeMember StatusCode_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* QualifiedName */ +static UA_DataTypeMember QualifiedName_members[2] = { +{ + UA_TYPENAME("namespaceIndex") /* .memberName */ + UA_TYPES_INT16, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("name") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_QualifiedName, name) - offsetof(UA_QualifiedName, namespaceIndex) - sizeof(UA_Int16), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* LocalizedText */ +static UA_DataTypeMember LocalizedText_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ExtensionObject */ +static UA_DataTypeMember ExtensionObject_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DataValue */ +static UA_DataTypeMember DataValue_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Variant */ +static UA_DataTypeMember Variant_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DiagnosticInfo */ +static UA_DataTypeMember DiagnosticInfo_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SignedSoftwareCertificate */ +static UA_DataTypeMember SignedSoftwareCertificate_members[2] = { +{ + UA_TYPENAME("certificateData") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("signature") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_SignedSoftwareCertificate, signature) - offsetof(UA_SignedSoftwareCertificate, certificateData) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SemanticChangeStructureDataType */ +static UA_DataTypeMember SemanticChangeStructureDataType_members[2] = { +{ + UA_TYPENAME("affected") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("affectedType") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_SemanticChangeStructureDataType, affectedType) - offsetof(UA_SemanticChangeStructureDataType, affected) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* StatusChangeNotification */ +static UA_DataTypeMember StatusChangeNotification_members[2] = { +{ + UA_TYPENAME("status") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfo") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_StatusChangeNotification, diagnosticInfo) - offsetof(UA_StatusChangeNotification, status) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BrowsePathTarget */ +static UA_DataTypeMember BrowsePathTarget_members[2] = { +{ + UA_TYPENAME("targetId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("remainingPathIndex") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_BrowsePathTarget, remainingPathIndex) - offsetof(UA_BrowsePathTarget, targetId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ViewAttributes */ +static UA_DataTypeMember ViewAttributes_members[7] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ViewAttributes, displayName) - offsetof(UA_ViewAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ViewAttributes, description) - offsetof(UA_ViewAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ViewAttributes, writeMask) - offsetof(UA_ViewAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ViewAttributes, userWriteMask) - offsetof(UA_ViewAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("containsNoLoops") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_ViewAttributes, containsNoLoops) - offsetof(UA_ViewAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("eventNotifier") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_ViewAttributes, eventNotifier) - offsetof(UA_ViewAttributes, containsNoLoops) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RequestHeader */ +static UA_DataTypeMember RequestHeader_members[7] = { +{ + UA_TYPENAME("authenticationToken") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("timestamp") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_RequestHeader, timestamp) - offsetof(UA_RequestHeader, authenticationToken) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestHandle") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_RequestHeader, requestHandle) - offsetof(UA_RequestHeader, timestamp) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("returnDiagnostics") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_RequestHeader, returnDiagnostics) - offsetof(UA_RequestHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("auditEntryId") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_RequestHeader, auditEntryId) - offsetof(UA_RequestHeader, returnDiagnostics) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("timeoutHint") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_RequestHeader, timeoutHint) - offsetof(UA_RequestHeader, auditEntryId) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("additionalHeader") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_RequestHeader, additionalHeader) - offsetof(UA_RequestHeader, timeoutHint) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* MonitoredItemModifyResult */ +static UA_DataTypeMember MonitoredItemModifyResult_members[4] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedSamplingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemModifyResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedQueueSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("filterResult") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemModifyResult, filterResult) - offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ElementOperand */ +static UA_DataTypeMember ElementOperand_members[1] = { +{ + UA_TYPENAME("index") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* CloseSecureChannelRequest */ +static UA_DataTypeMember CloseSecureChannelRequest_members[1] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AddNodesResult */ +static UA_DataTypeMember AddNodesResult_members[2] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("addedNodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_AddNodesResult, addedNodeId) - offsetof(UA_AddNodesResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* VariableAttributes */ +static UA_DataTypeMember VariableAttributes_members[13] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, displayName) - offsetof(UA_VariableAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, description) - offsetof(UA_VariableAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, writeMask) - offsetof(UA_VariableAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, userWriteMask) - offsetof(UA_VariableAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("value") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, value) - offsetof(UA_VariableAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataType") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, dataType) - offsetof(UA_VariableAttributes, value) - sizeof(UA_Variant), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("valueRank") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, valueRank) - offsetof(UA_VariableAttributes, dataType) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("arrayDimensions") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, arrayDimensionsSize) - offsetof(UA_VariableAttributes, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("accessLevel") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, accessLevel) - offsetof(UA_VariableAttributes, arrayDimensions) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userAccessLevel") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, userAccessLevel) - offsetof(UA_VariableAttributes, accessLevel) - sizeof(UA_Byte), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("minimumSamplingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, minimumSamplingInterval) - offsetof(UA_VariableAttributes, userAccessLevel) - sizeof(UA_Byte), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("historizing") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_VariableAttributes, historizing) - offsetof(UA_VariableAttributes, minimumSamplingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* NotificationMessage */ +static UA_DataTypeMember NotificationMessage_members[3] = { +{ + UA_TYPENAME("sequenceNumber") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_NotificationMessage, publishTime) - offsetof(UA_NotificationMessage, sequenceNumber) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("notificationData") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_NotificationMessage, notificationDataSize) - offsetof(UA_NotificationMessage, publishTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* FindServersOnNetworkRequest */ +static UA_DataTypeMember FindServersOnNetworkRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("startingRecordId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_FindServersOnNetworkRequest, startingRecordId) - offsetof(UA_FindServersOnNetworkRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxRecordsToReturn") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_FindServersOnNetworkRequest, maxRecordsToReturn) - offsetof(UA_FindServersOnNetworkRequest, startingRecordId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverCapabilityFilter") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_FindServersOnNetworkRequest, serverCapabilityFilterSize) - offsetof(UA_FindServersOnNetworkRequest, maxRecordsToReturn) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* EventFieldList */ +static UA_DataTypeMember EventFieldList_members[2] = { +{ + UA_TYPENAME("clientHandle") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("eventFields") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + offsetof(UA_EventFieldList, eventFieldsSize) - offsetof(UA_EventFieldList, clientHandle) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* MonitoringMode */ +static UA_DataTypeMember MonitoringMode_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* MdnsDiscoveryConfiguration */ +static UA_DataTypeMember MdnsDiscoveryConfiguration_members[2] = { +{ + UA_TYPENAME("mdnsServerName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverCapabilities") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_MdnsDiscoveryConfiguration, serverCapabilitiesSize) - offsetof(UA_MdnsDiscoveryConfiguration, mdnsServerName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CallMethodResult */ +static UA_DataTypeMember CallMethodResult_members[4] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("inputArgumentResults") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_CallMethodResult, inputArgumentResultsSize) - offsetof(UA_CallMethodResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("inputArgumentDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfosSize) - offsetof(UA_CallMethodResult, inputArgumentResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("outputArguments") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + offsetof(UA_CallMethodResult, outputArgumentsSize) - offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfos) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ParsingResult */ +static UA_DataTypeMember ParsingResult_members[3] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataStatusCodes") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_ParsingResult, dataStatusCodesSize) - offsetof(UA_ParsingResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("dataDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ParsingResult, dataDiagnosticInfosSize) - offsetof(UA_ParsingResult, dataStatusCodes) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RelativePathElement */ +static UA_DataTypeMember RelativePathElement_members[4] = { +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isInverse") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_RelativePathElement, isInverse) - offsetof(UA_RelativePathElement, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("includeSubtypes") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_RelativePathElement, includeSubtypes) - offsetof(UA_RelativePathElement, isInverse) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targetName") /* .memberName */ + UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + offsetof(UA_RelativePathElement, targetName) - offsetof(UA_RelativePathElement, includeSubtypes) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BrowseDirection */ +static UA_DataTypeMember BrowseDirection_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* CallMethodRequest */ +static UA_DataTypeMember CallMethodRequest_members[3] = { +{ + UA_TYPENAME("objectId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("methodId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_CallMethodRequest, methodId) - offsetof(UA_CallMethodRequest, objectId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("inputArguments") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + offsetof(UA_CallMethodRequest, inputArgumentsSize) - offsetof(UA_CallMethodRequest, methodId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RedundancySupport */ +static UA_DataTypeMember RedundancySupport_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* EventNotificationList */ +static UA_DataTypeMember EventNotificationList_members[1] = { +{ + UA_TYPENAME("events") /* .memberName */ + UA_TYPES_EVENTFIELDLIST, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* UnregisterNodesRequest */ +static UA_DataTypeMember UnregisterNodesRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToUnregister") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_UnregisterNodesRequest, nodesToUnregisterSize) - offsetof(UA_UnregisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ContentFilterElementResult */ +static UA_DataTypeMember ContentFilterElementResult_members[3] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("operandStatusCodes") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_ContentFilterElementResult, operandStatusCodesSize) - offsetof(UA_ContentFilterElementResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("operandDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ContentFilterElementResult, operandDiagnosticInfosSize) - offsetof(UA_ContentFilterElementResult, operandStatusCodes) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* SimpleAttributeOperand */ +static UA_DataTypeMember SimpleAttributeOperand_members[4] = { +{ + UA_TYPENAME("typeDefinitionId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browsePath") /* .memberName */ + UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + offsetof(UA_SimpleAttributeOperand, browsePathSize) - offsetof(UA_SimpleAttributeOperand, typeDefinitionId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("attributeId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SimpleAttributeOperand, attributeId) - offsetof(UA_SimpleAttributeOperand, browsePath) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("indexRange") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SimpleAttributeOperand, indexRange) - offsetof(UA_SimpleAttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* LiteralOperand */ +static UA_DataTypeMember LiteralOperand_members[1] = { +{ + UA_TYPENAME("value") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* QueryDataSet */ +static UA_DataTypeMember QueryDataSet_members[3] = { +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("typeDefinitionNode") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_QueryDataSet, typeDefinitionNode) - offsetof(UA_QueryDataSet, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("values") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + offsetof(UA_QueryDataSet, valuesSize) - offsetof(UA_QueryDataSet, typeDefinitionNode) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* AnonymousIdentityToken */ +static UA_DataTypeMember AnonymousIdentityToken_members[1] = { +{ + UA_TYPENAME("policyId") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SetPublishingModeRequest */ +static UA_DataTypeMember SetPublishingModeRequest_members[3] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishingEnabled") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_SetPublishingModeRequest, publishingEnabled) - offsetof(UA_SetPublishingModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionIds") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetPublishingModeRequest, subscriptionIdsSize) - offsetof(UA_SetPublishingModeRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* MonitoredItemCreateResult */ +static UA_DataTypeMember MonitoredItemCreateResult_members[5] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoredItemId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - offsetof(UA_MonitoredItemCreateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedSamplingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedQueueSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("filterResult") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemCreateResult, filterResult) - offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* TimestampsToReturn */ +static UA_DataTypeMember TimestampsToReturn_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* CallRequest */ +static UA_DataTypeMember CallRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("methodsToCall") /* .memberName */ + UA_TYPES_CALLMETHODREQUEST, /* .memberTypeIndex */ + offsetof(UA_CallRequest, methodsToCallSize) - offsetof(UA_CallRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* MethodAttributes */ +static UA_DataTypeMember MethodAttributes_members[7] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_MethodAttributes, displayName) - offsetof(UA_MethodAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_MethodAttributes, description) - offsetof(UA_MethodAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_MethodAttributes, writeMask) - offsetof(UA_MethodAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_MethodAttributes, userWriteMask) - offsetof(UA_MethodAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("executable") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_MethodAttributes, executable) - offsetof(UA_MethodAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userExecutable") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_MethodAttributes, userExecutable) - offsetof(UA_MethodAttributes, executable) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeleteReferencesItem */ +static UA_DataTypeMember DeleteReferencesItem_members[5] = { +{ + UA_TYPENAME("sourceNodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesItem, referenceTypeId) - offsetof(UA_DeleteReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isForward") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesItem, isForward) - offsetof(UA_DeleteReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targetNodeId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesItem, targetNodeId) - offsetof(UA_DeleteReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteBidirectional") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesItem, deleteBidirectional) - offsetof(UA_DeleteReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* WriteValue */ +static UA_DataTypeMember WriteValue_members[4] = { +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("attributeId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_WriteValue, attributeId) - offsetof(UA_WriteValue, nodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("indexRange") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_WriteValue, indexRange) - offsetof(UA_WriteValue, attributeId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("value") /* .memberName */ + UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + offsetof(UA_WriteValue, value) - offsetof(UA_WriteValue, indexRange) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* NodeAttributesMask */ +static UA_DataTypeMember NodeAttributesMask_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* MessageSecurityMode */ +static UA_DataTypeMember MessageSecurityMode_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* MonitoringParameters */ +static UA_DataTypeMember MonitoringParameters_members[5] = { +{ + UA_TYPENAME("clientHandle") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("samplingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_MonitoringParameters, samplingInterval) - offsetof(UA_MonitoringParameters, clientHandle) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("filter") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_MonitoringParameters, filter) - offsetof(UA_MonitoringParameters, samplingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("queueSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_MonitoringParameters, queueSize) - offsetof(UA_MonitoringParameters, filter) - sizeof(UA_ExtensionObject), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discardOldest") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_MonitoringParameters, discardOldest) - offsetof(UA_MonitoringParameters, queueSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ReferenceNode */ +static UA_DataTypeMember ReferenceNode_members[3] = { +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isInverse") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_ReferenceNode, isInverse) - offsetof(UA_ReferenceNode, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targetId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_ReferenceNode, targetId) - offsetof(UA_ReferenceNode, isInverse) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* Argument */ +static UA_DataTypeMember Argument_members[5] = { +{ + UA_TYPENAME("name") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataType") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_Argument, dataType) - offsetof(UA_Argument, name) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("valueRank") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + offsetof(UA_Argument, valueRank) - offsetof(UA_Argument, dataType) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("arrayDimensions") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_Argument, arrayDimensionsSize) - offsetof(UA_Argument, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_Argument, description) - offsetof(UA_Argument, arrayDimensions) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ChannelSecurityToken */ +static UA_DataTypeMember ChannelSecurityToken_members[4] = { +{ + UA_TYPENAME("channelId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("tokenId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ChannelSecurityToken, tokenId) - offsetof(UA_ChannelSecurityToken, channelId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("createdAt") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_ChannelSecurityToken, createdAt) - offsetof(UA_ChannelSecurityToken, tokenId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedLifetime") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ChannelSecurityToken, revisedLifetime) - offsetof(UA_ChannelSecurityToken, createdAt) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UserIdentityToken */ +static UA_DataTypeMember UserIdentityToken_members[1] = { +{ + UA_TYPENAME("policyId") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SignatureData */ +static UA_DataTypeMember SignatureData_members[2] = { +{ + UA_TYPENAME("algorithm") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("signature") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_SignatureData, signature) - offsetof(UA_SignatureData, algorithm) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ObjectTypeAttributes */ +static UA_DataTypeMember ObjectTypeAttributes_members[6] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ObjectTypeAttributes, displayName) - offsetof(UA_ObjectTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ObjectTypeAttributes, description) - offsetof(UA_ObjectTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ObjectTypeAttributes, writeMask) - offsetof(UA_ObjectTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ObjectTypeAttributes, userWriteMask) - offsetof(UA_ObjectTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isAbstract") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_ObjectTypeAttributes, isAbstract) - offsetof(UA_ObjectTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeadbandType */ +static UA_DataTypeMember DeadbandType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SecurityTokenRequestType */ +static UA_DataTypeMember SecurityTokenRequestType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* NodeAttributes */ +static UA_DataTypeMember NodeAttributes_members[5] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_NodeAttributes, displayName) - offsetof(UA_NodeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_NodeAttributes, description) - offsetof(UA_NodeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_NodeAttributes, writeMask) - offsetof(UA_NodeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_NodeAttributes, userWriteMask) - offsetof(UA_NodeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DataChangeTrigger */ +static UA_DataTypeMember DataChangeTrigger_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BuildInfo */ +static UA_DataTypeMember BuildInfo_members[6] = { +{ + UA_TYPENAME("productUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("manufacturerName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_BuildInfo, manufacturerName) - offsetof(UA_BuildInfo, productUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("productName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_BuildInfo, productName) - offsetof(UA_BuildInfo, manufacturerName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("softwareVersion") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_BuildInfo, softwareVersion) - offsetof(UA_BuildInfo, productName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("buildNumber") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_BuildInfo, buildNumber) - offsetof(UA_BuildInfo, softwareVersion) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("buildDate") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_BuildInfo, buildDate) - offsetof(UA_BuildInfo, buildNumber) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* NodeClass */ +static UA_DataTypeMember NodeClass_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SubscriptionDiagnosticsDataType */ +static UA_DataTypeMember SubscriptionDiagnosticsDataType_members[31] = { +{ + UA_TYPENAME("sessionId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, subscriptionId) - offsetof(UA_SubscriptionDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("priority") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, priority) - offsetof(UA_SubscriptionDiagnosticsDataType, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, publishingInterval) - offsetof(UA_SubscriptionDiagnosticsDataType, priority) - sizeof(UA_Byte), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxKeepAliveCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, maxKeepAliveCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxLifetimeCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, maxLifetimeCount) - offsetof(UA_SubscriptionDiagnosticsDataType, maxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxNotificationsPerPublish") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, maxNotificationsPerPublish) - offsetof(UA_SubscriptionDiagnosticsDataType, maxLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishingEnabled") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, publishingEnabled) - offsetof(UA_SubscriptionDiagnosticsDataType, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("modifyCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, modifyCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("enableCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, enableCount) - offsetof(UA_SubscriptionDiagnosticsDataType, modifyCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("disableCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, disableCount) - offsetof(UA_SubscriptionDiagnosticsDataType, enableCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("republishRequestCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, republishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, disableCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("republishMessageRequestCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishRequestCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("republishMessageCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageRequestCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("transferRequestCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, transferRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("transferredToAltClientCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, transferredToAltClientCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferRequestCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("transferredToSameClientCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, transferredToSameClientCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferredToAltClientCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishRequestCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, publishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferredToSameClientCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataChangeNotificationsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, dataChangeNotificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishRequestCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("eventNotificationsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, eventNotificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, dataChangeNotificationsCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("notificationsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, notificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, eventNotificationsCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("latePublishRequestCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, latePublishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, notificationsCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentKeepAliveCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, currentKeepAliveCount) - offsetof(UA_SubscriptionDiagnosticsDataType, latePublishRequestCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentLifetimeCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, currentLifetimeCount) - offsetof(UA_SubscriptionDiagnosticsDataType, currentKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("unacknowledgedMessageCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, unacknowledgedMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, currentLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discardedMessageCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, discardedMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, unacknowledgedMessageCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoredItemCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, monitoredItemCount) - offsetof(UA_SubscriptionDiagnosticsDataType, discardedMessageCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("disabledMonitoredItemCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, disabledMonitoredItemCount) - offsetof(UA_SubscriptionDiagnosticsDataType, monitoredItemCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoringQueueOverflowCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, monitoringQueueOverflowCount) - offsetof(UA_SubscriptionDiagnosticsDataType, disabledMonitoredItemCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nextSequenceNumber") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, nextSequenceNumber) - offsetof(UA_SubscriptionDiagnosticsDataType, monitoringQueueOverflowCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("eventQueueOverFlowCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionDiagnosticsDataType, eventQueueOverFlowCount) - offsetof(UA_SubscriptionDiagnosticsDataType, nextSequenceNumber) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* FilterOperand */ +#define FilterOperand_members NULL + +/* MonitoredItemNotification */ +static UA_DataTypeMember MonitoredItemNotification_members[2] = { +{ + UA_TYPENAME("clientHandle") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("value") /* .memberName */ + UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemNotification, value) - offsetof(UA_MonitoredItemNotification, clientHandle) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeleteNodesItem */ +static UA_DataTypeMember DeleteNodesItem_members[2] = { +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteTargetReferences") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_DeleteNodesItem, deleteTargetReferences) - offsetof(UA_DeleteNodesItem, nodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeleteSubscriptionsRequest */ +static UA_DataTypeMember DeleteSubscriptionsRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionIds") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_DeleteSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_DeleteSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* SubscriptionAcknowledgement */ +static UA_DataTypeMember SubscriptionAcknowledgement_members[2] = { +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sequenceNumber") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SubscriptionAcknowledgement, sequenceNumber) - offsetof(UA_SubscriptionAcknowledgement, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ReadValueId */ +static UA_DataTypeMember ReadValueId_members[4] = { +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("attributeId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ReadValueId, attributeId) - offsetof(UA_ReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("indexRange") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ReadValueId, indexRange) - offsetof(UA_ReadValueId, attributeId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataEncoding") /* .memberName */ + UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + offsetof(UA_ReadValueId, dataEncoding) - offsetof(UA_ReadValueId, indexRange) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DataTypeAttributes */ +static UA_DataTypeMember DataTypeAttributes_members[6] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_DataTypeAttributes, displayName) - offsetof(UA_DataTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_DataTypeAttributes, description) - offsetof(UA_DataTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_DataTypeAttributes, writeMask) - offsetof(UA_DataTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_DataTypeAttributes, userWriteMask) - offsetof(UA_DataTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isAbstract") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_DataTypeAttributes, isAbstract) - offsetof(UA_DataTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ResponseHeader */ +static UA_DataTypeMember ResponseHeader_members[6] = { +{ + UA_TYPENAME("timestamp") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestHandle") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ResponseHeader, requestHandle) - offsetof(UA_ResponseHeader, timestamp) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serviceResult") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_ResponseHeader, serviceResult) - offsetof(UA_ResponseHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serviceDiagnostics") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ResponseHeader, serviceDiagnostics) - offsetof(UA_ResponseHeader, serviceResult) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("stringTable") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ResponseHeader, stringTableSize) - offsetof(UA_ResponseHeader, serviceDiagnostics) - sizeof(UA_DiagnosticInfo), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("additionalHeader") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_ResponseHeader, additionalHeader) - offsetof(UA_ResponseHeader, stringTable) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeleteMonitoredItemsRequest */ +static UA_DataTypeMember DeleteMonitoredItemsRequest_members[3] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - offsetof(UA_DeleteMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoredItemIds") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_DeleteMonitoredItemsRequest, monitoredItemIdsSize) - offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ViewDescription */ +static UA_DataTypeMember ViewDescription_members[3] = { +{ + UA_TYPENAME("viewId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("timestamp") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_ViewDescription, timestamp) - offsetof(UA_ViewDescription, viewId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("viewVersion") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ViewDescription, viewVersion) - offsetof(UA_ViewDescription, timestamp) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ServerOnNetwork */ +static UA_DataTypeMember ServerOnNetwork_members[4] = { +{ + UA_TYPENAME("recordId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ServerOnNetwork, serverName) - offsetof(UA_ServerOnNetwork, recordId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discoveryUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ServerOnNetwork, discoveryUrl) - offsetof(UA_ServerOnNetwork, serverName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverCapabilities") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ServerOnNetwork, serverCapabilitiesSize) - offsetof(UA_ServerOnNetwork, discoveryUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DeleteMonitoredItemsResponse */ +static UA_DataTypeMember DeleteMonitoredItemsResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_DeleteMonitoredItemsResponse, resultsSize) - offsetof(UA_DeleteMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_DeleteMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_DeleteMonitoredItemsResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* FindServersOnNetworkResponse */ +static UA_DataTypeMember FindServersOnNetworkResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("lastCounterResetTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_FindServersOnNetworkResponse, lastCounterResetTime) - offsetof(UA_FindServersOnNetworkResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("servers") /* .memberName */ + UA_TYPES_SERVERONNETWORK, /* .memberTypeIndex */ + offsetof(UA_FindServersOnNetworkResponse, serversSize) - offsetof(UA_FindServersOnNetworkResponse, lastCounterResetTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RelativePath */ +static UA_DataTypeMember RelativePath_members[1] = { +{ + UA_TYPENAME("elements") /* .memberName */ + UA_TYPES_RELATIVEPATHELEMENT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RegisterNodesRequest */ +static UA_DataTypeMember RegisterNodesRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToRegister") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_RegisterNodesRequest, nodesToRegisterSize) - offsetof(UA_RegisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* AggregateConfiguration */ +static UA_DataTypeMember AggregateConfiguration_members[5] = { +{ + UA_TYPENAME("useServerCapabilitiesDefaults") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("treatUncertainAsBad") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - offsetof(UA_AggregateConfiguration, useServerCapabilitiesDefaults) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("percentDataBad") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_AggregateConfiguration, percentDataBad) - offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("percentDataGood") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_AggregateConfiguration, percentDataGood) - offsetof(UA_AggregateConfiguration, percentDataBad) - sizeof(UA_Byte), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("useSlopedExtrapolation") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_AggregateConfiguration, useSlopedExtrapolation) - offsetof(UA_AggregateConfiguration, percentDataGood) - sizeof(UA_Byte), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeleteNodesRequest */ +static UA_DataTypeMember DeleteNodesRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToDelete") /* .memberName */ + UA_TYPES_DELETENODESITEM, /* .memberTypeIndex */ + offsetof(UA_DeleteNodesRequest, nodesToDeleteSize) - offsetof(UA_DeleteNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* PublishResponse */ +static UA_DataTypeMember PublishResponse_members[7] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_PublishResponse, subscriptionId) - offsetof(UA_PublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("availableSequenceNumbers") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_PublishResponse, availableSequenceNumbersSize) - offsetof(UA_PublishResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("moreNotifications") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_PublishResponse, moreNotifications) - offsetof(UA_PublishResponse, availableSequenceNumbers) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("notificationMessage") /* .memberName */ + UA_TYPES_NOTIFICATIONMESSAGE, /* .memberTypeIndex */ + offsetof(UA_PublishResponse, notificationMessage) - offsetof(UA_PublishResponse, moreNotifications) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_PublishResponse, resultsSize) - offsetof(UA_PublishResponse, notificationMessage) - sizeof(UA_NotificationMessage), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_PublishResponse, diagnosticInfosSize) - offsetof(UA_PublishResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* MonitoredItemModifyRequest */ +static UA_DataTypeMember MonitoredItemModifyRequest_members[2] = { +{ + UA_TYPENAME("monitoredItemId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedParameters") /* .memberName */ + UA_TYPES_MONITORINGPARAMETERS, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemModifyRequest, requestedParameters) - offsetof(UA_MonitoredItemModifyRequest, monitoredItemId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ServiceCounterDataType */ +static UA_DataTypeMember ServiceCounterDataType_members[2] = { +{ + UA_TYPENAME("totalCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("errorCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServiceCounterDataType, errorCount) - offsetof(UA_ServiceCounterDataType, totalCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ModelChangeStructureDataType */ +static UA_DataTypeMember ModelChangeStructureDataType_members[3] = { +{ + UA_TYPENAME("affected") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("affectedType") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_ModelChangeStructureDataType, affectedType) - offsetof(UA_ModelChangeStructureDataType, affected) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("verb") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_ModelChangeStructureDataType, verb) - offsetof(UA_ModelChangeStructureDataType, affectedType) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UserNameIdentityToken */ +static UA_DataTypeMember UserNameIdentityToken_members[4] = { +{ + UA_TYPENAME("policyId") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_UserNameIdentityToken, userName) - offsetof(UA_UserNameIdentityToken, policyId) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("password") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_UserNameIdentityToken, password) - offsetof(UA_UserNameIdentityToken, userName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("encryptionAlgorithm") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_UserNameIdentityToken, encryptionAlgorithm) - offsetof(UA_UserNameIdentityToken, password) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* IdType */ +static UA_DataTypeMember IdType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UserTokenType */ +static UA_DataTypeMember UserTokenType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SetTriggeringResponse */ +static UA_DataTypeMember SetTriggeringResponse_members[5] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("addResults") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringResponse, addResultsSize) - offsetof(UA_SetTriggeringResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("addDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringResponse, addDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, addResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("removeResults") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringResponse, removeResultsSize) - offsetof(UA_SetTriggeringResponse, addDiagnosticInfos) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("removeDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringResponse, removeDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, removeResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* TimeZoneDataType */ +static UA_DataTypeMember TimeZoneDataType_members[2] = { +{ + UA_TYPENAME("offset") /* .memberName */ + UA_TYPES_INT16, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("daylightSavingInOffset") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_TimeZoneDataType, daylightSavingInOffset) - offsetof(UA_TimeZoneDataType, offset) - sizeof(UA_Int16), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ActivateSessionRequest */ +static UA_DataTypeMember ActivateSessionRequest_members[6] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientSignature") /* .memberName */ + UA_TYPES_SIGNATUREDATA, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionRequest, clientSignature) - offsetof(UA_ActivateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientSoftwareCertificates") /* .memberName */ + UA_TYPES_SIGNEDSOFTWARECERTIFICATE, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionRequest, clientSoftwareCertificatesSize) - offsetof(UA_ActivateSessionRequest, clientSignature) - sizeof(UA_SignatureData), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("localeIds") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionRequest, localeIdsSize) - offsetof(UA_ActivateSessionRequest, clientSoftwareCertificates) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("userIdentityToken") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionRequest, userIdentityToken) - offsetof(UA_ActivateSessionRequest, localeIds) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userTokenSignature") /* .memberName */ + UA_TYPES_SIGNATUREDATA, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionRequest, userTokenSignature) - offsetof(UA_ActivateSessionRequest, userIdentityToken) - sizeof(UA_ExtensionObject), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* OpenSecureChannelResponse */ +static UA_DataTypeMember OpenSecureChannelResponse_members[4] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverProtocolVersion") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - offsetof(UA_OpenSecureChannelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityToken") /* .memberName */ + UA_TYPES_CHANNELSECURITYTOKEN, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelResponse, securityToken) - offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverNonce") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelResponse, serverNonce) - offsetof(UA_OpenSecureChannelResponse, securityToken) - sizeof(UA_ChannelSecurityToken), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ApplicationType */ +static UA_DataTypeMember ApplicationType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ServerState */ +static UA_DataTypeMember ServerState_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* QueryNextResponse */ +static UA_DataTypeMember QueryNextResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("queryDataSets") /* .memberName */ + UA_TYPES_QUERYDATASET, /* .memberTypeIndex */ + offsetof(UA_QueryNextResponse, queryDataSetsSize) - offsetof(UA_QueryNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("revisedContinuationPoint") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_QueryNextResponse, revisedContinuationPoint) - offsetof(UA_QueryNextResponse, queryDataSets) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DiscoveryConfiguration */ +#define DiscoveryConfiguration_members NULL + +/* ActivateSessionResponse */ +static UA_DataTypeMember ActivateSessionResponse_members[4] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverNonce") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionResponse, serverNonce) - offsetof(UA_ActivateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionResponse, resultsSize) - offsetof(UA_ActivateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ActivateSessionResponse, diagnosticInfosSize) - offsetof(UA_ActivateSessionResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* EndpointUrlListDataType */ +static UA_DataTypeMember EndpointUrlListDataType_members[1] = { +{ + UA_TYPENAME("endpointUrlList") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* FilterOperator */ +static UA_DataTypeMember FilterOperator_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* QueryNextRequest */ +static UA_DataTypeMember QueryNextRequest_members[3] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("releaseContinuationPoint") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_QueryNextRequest, releaseContinuationPoint) - offsetof(UA_QueryNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("continuationPoint") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_QueryNextRequest, continuationPoint) - offsetof(UA_QueryNextRequest, releaseContinuationPoint) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* WriteResponse */ +static UA_DataTypeMember WriteResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_WriteResponse, resultsSize) - offsetof(UA_WriteResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_WriteResponse, diagnosticInfosSize) - offsetof(UA_WriteResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* BrowseNextRequest */ +static UA_DataTypeMember BrowseNextRequest_members[3] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("releaseContinuationPoints") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - offsetof(UA_BrowseNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("continuationPoints") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_BrowseNextRequest, continuationPointsSize) - offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CreateSubscriptionRequest */ +static UA_DataTypeMember CreateSubscriptionRequest_members[7] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedPublishingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - offsetof(UA_CreateSubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedLifetimeCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedMaxKeepAliveCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxNotificationsPerPublish") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishingEnabled") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("priority") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionRequest, priority) - offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* VariableTypeAttributes */ +static UA_DataTypeMember VariableTypeAttributes_members[10] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, displayName) - offsetof(UA_VariableTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, description) - offsetof(UA_VariableTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, writeMask) - offsetof(UA_VariableTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, userWriteMask) - offsetof(UA_VariableTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("value") /* .memberName */ + UA_TYPES_VARIANT, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, value) - offsetof(UA_VariableTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataType") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, dataType) - offsetof(UA_VariableTypeAttributes, value) - sizeof(UA_Variant), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("valueRank") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, valueRank) - offsetof(UA_VariableTypeAttributes, dataType) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("arrayDimensions") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, arrayDimensionsSize) - offsetof(UA_VariableTypeAttributes, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("isAbstract") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_VariableTypeAttributes, isAbstract) - offsetof(UA_VariableTypeAttributes, arrayDimensions) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BrowsePathResult */ +static UA_DataTypeMember BrowsePathResult_members[2] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targets") /* .memberName */ + UA_TYPES_BROWSEPATHTARGET, /* .memberTypeIndex */ + offsetof(UA_BrowsePathResult, targetsSize) - offsetof(UA_BrowsePathResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ModifySubscriptionResponse */ +static UA_DataTypeMember ModifySubscriptionResponse_members[4] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedPublishingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - offsetof(UA_ModifySubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedLifetimeCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedMaxKeepAliveCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RedundantServerDataType */ +static UA_DataTypeMember RedundantServerDataType_members[3] = { +{ + UA_TYPENAME("serverId") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serviceLevel") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_RedundantServerDataType, serviceLevel) - offsetof(UA_RedundantServerDataType, serverId) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverState") /* .memberName */ + UA_TYPES_SERVERSTATE, /* .memberTypeIndex */ + offsetof(UA_RedundantServerDataType, serverState) - offsetof(UA_RedundantServerDataType, serviceLevel) - sizeof(UA_Byte), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RegisterNodesResponse */ +static UA_DataTypeMember RegisterNodesResponse_members[2] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("registeredNodeIds") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_RegisterNodesResponse, registeredNodeIdsSize) - offsetof(UA_RegisterNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CloseSessionRequest */ +static UA_DataTypeMember CloseSessionRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteSubscriptions") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_CloseSessionRequest, deleteSubscriptions) - offsetof(UA_CloseSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ModifyMonitoredItemsResponse */ +static UA_DataTypeMember ModifyMonitoredItemsResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_MONITOREDITEMMODIFYRESULT, /* .memberTypeIndex */ + offsetof(UA_ModifyMonitoredItemsResponse, resultsSize) - offsetof(UA_ModifyMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ModifyMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_ModifyMonitoredItemsResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ModifySubscriptionRequest */ +static UA_DataTypeMember ModifySubscriptionRequest_members[7] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionRequest, subscriptionId) - offsetof(UA_ModifySubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedPublishingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - offsetof(UA_ModifySubscriptionRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedLifetimeCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedMaxKeepAliveCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxNotificationsPerPublish") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("priority") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_ModifySubscriptionRequest, priority) - offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ServerDiagnosticsSummaryDataType */ +static UA_DataTypeMember ServerDiagnosticsSummaryDataType_members[12] = { +{ + UA_TYPENAME("serverViewCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentSessionCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, serverViewCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("cumulatedSessionCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityRejectedSessionCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("rejectedSessionCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sessionTimeoutCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sessionAbortCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentSubscriptionCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("cumulatedSubscriptionCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishingIntervalCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityRejectedRequestsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("rejectedRequestsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* UserTokenPolicy */ +static UA_DataTypeMember UserTokenPolicy_members[5] = { +{ + UA_TYPENAME("policyId") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("tokenType") /* .memberName */ + UA_TYPES_USERTOKENTYPE, /* .memberTypeIndex */ + offsetof(UA_UserTokenPolicy, tokenType) - offsetof(UA_UserTokenPolicy, policyId) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("issuedTokenType") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_UserTokenPolicy, issuedTokenType) - offsetof(UA_UserTokenPolicy, tokenType) - sizeof(UA_UserTokenType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("issuerEndpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - offsetof(UA_UserTokenPolicy, issuedTokenType) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityPolicyUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_UserTokenPolicy, securityPolicyUri) - offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ReferenceTypeAttributes */ +static UA_DataTypeMember ReferenceTypeAttributes_members[8] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, displayName) - offsetof(UA_ReferenceTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, description) - offsetof(UA_ReferenceTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, writeMask) - offsetof(UA_ReferenceTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, userWriteMask) - offsetof(UA_ReferenceTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isAbstract") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, isAbstract) - offsetof(UA_ReferenceTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("symmetric") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, symmetric) - offsetof(UA_ReferenceTypeAttributes, isAbstract) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("inverseName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ReferenceTypeAttributes, inverseName) - offsetof(UA_ReferenceTypeAttributes, symmetric) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BrowsePath */ +static UA_DataTypeMember BrowsePath_members[2] = { +{ + UA_TYPENAME("startingNode") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("relativePath") /* .memberName */ + UA_TYPES_RELATIVEPATH, /* .memberTypeIndex */ + offsetof(UA_BrowsePath, relativePath) - offsetof(UA_BrowsePath, startingNode) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SetMonitoringModeRequest */ +static UA_DataTypeMember SetMonitoringModeRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetMonitoringModeRequest, subscriptionId) - offsetof(UA_SetMonitoringModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoringMode") /* .memberName */ + UA_TYPES_MONITORINGMODE, /* .memberTypeIndex */ + offsetof(UA_SetMonitoringModeRequest, monitoringMode) - offsetof(UA_SetMonitoringModeRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoredItemIds") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetMonitoringModeRequest, monitoredItemIdsSize) - offsetof(UA_SetMonitoringModeRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* UnregisterNodesResponse */ +static UA_DataTypeMember UnregisterNodesResponse_members[1] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* WriteRequest */ +static UA_DataTypeMember WriteRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToWrite") /* .memberName */ + UA_TYPES_WRITEVALUE, /* .memberTypeIndex */ + offsetof(UA_WriteRequest, nodesToWriteSize) - offsetof(UA_WriteRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ObjectAttributes */ +static UA_DataTypeMember ObjectAttributes_members[6] = { +{ + UA_TYPENAME("specifiedAttributes") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ObjectAttributes, displayName) - offsetof(UA_ObjectAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("description") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ObjectAttributes, description) - offsetof(UA_ObjectAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ObjectAttributes, writeMask) - offsetof(UA_ObjectAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userWriteMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ObjectAttributes, userWriteMask) - offsetof(UA_ObjectAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("eventNotifier") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_ObjectAttributes, eventNotifier) - offsetof(UA_ObjectAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BrowseResultMask */ +static UA_DataTypeMember BrowseResultMask_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* BrowseDescription */ +static UA_DataTypeMember BrowseDescription_members[6] = { +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browseDirection") /* .memberName */ + UA_TYPES_BROWSEDIRECTION, /* .memberTypeIndex */ + offsetof(UA_BrowseDescription, browseDirection) - offsetof(UA_BrowseDescription, nodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_BrowseDescription, referenceTypeId) - offsetof(UA_BrowseDescription, browseDirection) - sizeof(UA_BrowseDirection), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("includeSubtypes") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_BrowseDescription, includeSubtypes) - offsetof(UA_BrowseDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodeClassMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_BrowseDescription, nodeClassMask) - offsetof(UA_BrowseDescription, includeSubtypes) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("resultMask") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_BrowseDescription, resultMask) - offsetof(UA_BrowseDescription, nodeClassMask) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SetTriggeringRequest */ +static UA_DataTypeMember SetTriggeringRequest_members[5] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringRequest, subscriptionId) - offsetof(UA_SetTriggeringRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("triggeringItemId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringRequest, triggeringItemId) - offsetof(UA_SetTriggeringRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("linksToAdd") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringRequest, linksToAddSize) - offsetof(UA_SetTriggeringRequest, triggeringItemId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("linksToRemove") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SetTriggeringRequest, linksToRemoveSize) - offsetof(UA_SetTriggeringRequest, linksToAdd) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* SessionSecurityDiagnosticsDataType */ +static UA_DataTypeMember SessionSecurityDiagnosticsDataType_members[9] = { +{ + UA_TYPENAME("sessionId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientUserIdOfSession") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdOfSession) - offsetof(UA_SessionSecurityDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientUserIdHistory") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdHistorySize) - offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdOfSession) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("authenticationMechanism") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, authenticationMechanism) - offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdHistory) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("encoding") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, encoding) - offsetof(UA_SessionSecurityDiagnosticsDataType, authenticationMechanism) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("transportProtocol") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, transportProtocol) - offsetof(UA_SessionSecurityDiagnosticsDataType, encoding) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityMode") /* .memberName */ + UA_TYPES_MESSAGESECURITYMODE, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, securityMode) - offsetof(UA_SessionSecurityDiagnosticsDataType, transportProtocol) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityPolicyUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, securityPolicyUri) - offsetof(UA_SessionSecurityDiagnosticsDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientCertificate") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_SessionSecurityDiagnosticsDataType, clientCertificate) - offsetof(UA_SessionSecurityDiagnosticsDataType, securityPolicyUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RepublishRequest */ +static UA_DataTypeMember RepublishRequest_members[3] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_RepublishRequest, subscriptionId) - offsetof(UA_RepublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("retransmitSequenceNumber") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_RepublishRequest, retransmitSequenceNumber) - offsetof(UA_RepublishRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* GetEndpointsRequest */ +static UA_DataTypeMember GetEndpointsRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("endpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_GetEndpointsRequest, endpointUrl) - offsetof(UA_GetEndpointsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("localeIds") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_GetEndpointsRequest, localeIdsSize) - offsetof(UA_GetEndpointsRequest, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("profileUris") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_GetEndpointsRequest, profileUrisSize) - offsetof(UA_GetEndpointsRequest, localeIds) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* PublishRequest */ +static UA_DataTypeMember PublishRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionAcknowledgements") /* .memberName */ + UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT, /* .memberTypeIndex */ + offsetof(UA_PublishRequest, subscriptionAcknowledgementsSize) - offsetof(UA_PublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DeleteSubscriptionsResponse */ +static UA_DataTypeMember DeleteSubscriptionsResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_DeleteSubscriptionsResponse, resultsSize) - offsetof(UA_DeleteSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_DeleteSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_DeleteSubscriptionsResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* AddNodesResponse */ +static UA_DataTypeMember AddNodesResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_ADDNODESRESULT, /* .memberTypeIndex */ + offsetof(UA_AddNodesResponse, resultsSize) - offsetof(UA_AddNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_AddNodesResponse, diagnosticInfosSize) - offsetof(UA_AddNodesResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DataChangeNotification */ +static UA_DataTypeMember DataChangeNotification_members[2] = { +{ + UA_TYPENAME("monitoredItems") /* .memberName */ + UA_TYPES_MONITOREDITEMNOTIFICATION, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_DataChangeNotification, diagnosticInfosSize) - offsetof(UA_DataChangeNotification, monitoredItems) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CloseSecureChannelResponse */ +static UA_DataTypeMember CloseSecureChannelResponse_members[1] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ModifyMonitoredItemsRequest */ +static UA_DataTypeMember ModifyMonitoredItemsRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - offsetof(UA_ModifyMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("timestampsToReturn") /* .memberName */ + UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("itemsToModify") /* .memberName */ + UA_TYPES_MONITOREDITEMMODIFYREQUEST, /* .memberTypeIndex */ + offsetof(UA_ModifyMonitoredItemsRequest, itemsToModifySize) - offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* SetMonitoringModeResponse */ +static UA_DataTypeMember SetMonitoringModeResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_SetMonitoringModeResponse, resultsSize) - offsetof(UA_SetMonitoringModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_SetMonitoringModeResponse, diagnosticInfosSize) - offsetof(UA_SetMonitoringModeResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* FindServersRequest */ +static UA_DataTypeMember FindServersRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("endpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_FindServersRequest, endpointUrl) - offsetof(UA_FindServersRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("localeIds") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_FindServersRequest, localeIdsSize) - offsetof(UA_FindServersRequest, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("serverUris") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_FindServersRequest, serverUrisSize) - offsetof(UA_FindServersRequest, localeIds) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ReferenceDescription */ +static UA_DataTypeMember ReferenceDescription_members[7] = { +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isForward") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_ReferenceDescription, isForward) - offsetof(UA_ReferenceDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_ReferenceDescription, nodeId) - offsetof(UA_ReferenceDescription, isForward) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browseName") /* .memberName */ + UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + offsetof(UA_ReferenceDescription, browseName) - offsetof(UA_ReferenceDescription, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("displayName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ReferenceDescription, displayName) - offsetof(UA_ReferenceDescription, browseName) - sizeof(UA_QualifiedName), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodeClass") /* .memberName */ + UA_TYPES_NODECLASS, /* .memberTypeIndex */ + offsetof(UA_ReferenceDescription, nodeClass) - offsetof(UA_ReferenceDescription, displayName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("typeDefinition") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_ReferenceDescription, typeDefinition) - offsetof(UA_ReferenceDescription, nodeClass) - sizeof(UA_NodeClass), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SetPublishingModeResponse */ +static UA_DataTypeMember SetPublishingModeResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_SetPublishingModeResponse, resultsSize) - offsetof(UA_SetPublishingModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_SetPublishingModeResponse, diagnosticInfosSize) - offsetof(UA_SetPublishingModeResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ContentFilterResult */ +static UA_DataTypeMember ContentFilterResult_members[2] = { +{ + UA_TYPENAME("elementResults") /* .memberName */ + UA_TYPES_CONTENTFILTERELEMENTRESULT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("elementDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ContentFilterResult, elementDiagnosticInfosSize) - offsetof(UA_ContentFilterResult, elementResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RegisterServerResponse */ +static UA_DataTypeMember RegisterServerResponse_members[1] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AddReferencesItem */ +static UA_DataTypeMember AddReferencesItem_members[6] = { +{ + UA_TYPENAME("sourceNodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_AddReferencesItem, referenceTypeId) - offsetof(UA_AddReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isForward") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_AddReferencesItem, isForward) - offsetof(UA_AddReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targetServerUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_AddReferencesItem, targetServerUri) - offsetof(UA_AddReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targetNodeId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_AddReferencesItem, targetNodeId) - offsetof(UA_AddReferencesItem, targetServerUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("targetNodeClass") /* .memberName */ + UA_TYPES_NODECLASS, /* .memberTypeIndex */ + offsetof(UA_AddReferencesItem, targetNodeClass) - offsetof(UA_AddReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* QueryDataDescription */ +static UA_DataTypeMember QueryDataDescription_members[3] = { +{ + UA_TYPENAME("relativePath") /* .memberName */ + UA_TYPES_RELATIVEPATH, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("attributeId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_QueryDataDescription, attributeId) - offsetof(UA_QueryDataDescription, relativePath) - sizeof(UA_RelativePath), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("indexRange") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_QueryDataDescription, indexRange) - offsetof(UA_QueryDataDescription, attributeId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* CreateSubscriptionResponse */ +static UA_DataTypeMember CreateSubscriptionResponse_members[5] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionResponse, subscriptionId) - offsetof(UA_CreateSubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedPublishingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - offsetof(UA_CreateSubscriptionResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedLifetimeCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedMaxKeepAliveCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* NetworkGroupDataType */ +static UA_DataTypeMember NetworkGroupDataType_members[2] = { +{ + UA_TYPENAME("serverUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("networkPaths") /* .memberName */ + UA_TYPES_ENDPOINTURLLISTDATATYPE, /* .memberTypeIndex */ + offsetof(UA_NetworkGroupDataType, networkPathsSize) - offsetof(UA_NetworkGroupDataType, serverUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DeleteReferencesResponse */ +static UA_DataTypeMember DeleteReferencesResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesResponse, resultsSize) - offsetof(UA_DeleteReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesResponse, diagnosticInfosSize) - offsetof(UA_DeleteReferencesResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CreateMonitoredItemsResponse */ +static UA_DataTypeMember CreateMonitoredItemsResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_MONITOREDITEMCREATERESULT, /* .memberTypeIndex */ + offsetof(UA_CreateMonitoredItemsResponse, resultsSize) - offsetof(UA_CreateMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_CreateMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_CreateMonitoredItemsResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CallResponse */ +static UA_DataTypeMember CallResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_CALLMETHODRESULT, /* .memberTypeIndex */ + offsetof(UA_CallResponse, resultsSize) - offsetof(UA_CallResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_CallResponse, diagnosticInfosSize) - offsetof(UA_CallResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DeleteNodesResponse */ +static UA_DataTypeMember DeleteNodesResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_DeleteNodesResponse, resultsSize) - offsetof(UA_DeleteNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_DeleteNodesResponse, diagnosticInfosSize) - offsetof(UA_DeleteNodesResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RepublishResponse */ +static UA_DataTypeMember RepublishResponse_members[2] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("notificationMessage") /* .memberName */ + UA_TYPES_NOTIFICATIONMESSAGE, /* .memberTypeIndex */ + offsetof(UA_RepublishResponse, notificationMessage) - offsetof(UA_RepublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* MonitoredItemCreateRequest */ +static UA_DataTypeMember MonitoredItemCreateRequest_members[3] = { +{ + UA_TYPENAME("itemToMonitor") /* .memberName */ + UA_TYPES_READVALUEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("monitoringMode") /* .memberName */ + UA_TYPES_MONITORINGMODE, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - offsetof(UA_MonitoredItemCreateRequest, itemToMonitor) - sizeof(UA_ReadValueId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedParameters") /* .memberName */ + UA_TYPES_MONITORINGPARAMETERS, /* .memberTypeIndex */ + offsetof(UA_MonitoredItemCreateRequest, requestedParameters) - offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* DeleteReferencesRequest */ +static UA_DataTypeMember DeleteReferencesRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("referencesToDelete") /* .memberName */ + UA_TYPES_DELETEREFERENCESITEM, /* .memberTypeIndex */ + offsetof(UA_DeleteReferencesRequest, referencesToDeleteSize) - offsetof(UA_DeleteReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ReadResponse */ +static UA_DataTypeMember ReadResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_DATAVALUE, /* .memberTypeIndex */ + offsetof(UA_ReadResponse, resultsSize) - offsetof(UA_ReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_ReadResponse, diagnosticInfosSize) - offsetof(UA_ReadResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* AddReferencesRequest */ +static UA_DataTypeMember AddReferencesRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("referencesToAdd") /* .memberName */ + UA_TYPES_ADDREFERENCESITEM, /* .memberTypeIndex */ + offsetof(UA_AddReferencesRequest, referencesToAddSize) - offsetof(UA_AddReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ReadRequest */ +static UA_DataTypeMember ReadRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxAge") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_ReadRequest, maxAge) - offsetof(UA_ReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("timestampsToReturn") /* .memberName */ + UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + offsetof(UA_ReadRequest, timestampsToReturn) - offsetof(UA_ReadRequest, maxAge) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToRead") /* .memberName */ + UA_TYPES_READVALUEID, /* .memberTypeIndex */ + offsetof(UA_ReadRequest, nodesToReadSize) - offsetof(UA_ReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* OpenSecureChannelRequest */ +static UA_DataTypeMember OpenSecureChannelRequest_members[6] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientProtocolVersion") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - offsetof(UA_OpenSecureChannelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestType") /* .memberName */ + UA_TYPES_SECURITYTOKENREQUESTTYPE, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelRequest, requestType) - offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityMode") /* .memberName */ + UA_TYPES_MESSAGESECURITYMODE, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelRequest, securityMode) - offsetof(UA_OpenSecureChannelRequest, requestType) - sizeof(UA_SecurityTokenRequestType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientNonce") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelRequest, clientNonce) - offsetof(UA_OpenSecureChannelRequest, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedLifetime") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_OpenSecureChannelRequest, requestedLifetime) - offsetof(UA_OpenSecureChannelRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RegisterServer2Response */ +static UA_DataTypeMember RegisterServer2Response_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("configurationResults") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_RegisterServer2Response, configurationResultsSize) - offsetof(UA_RegisterServer2Response, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_RegisterServer2Response, diagnosticInfosSize) - offsetof(UA_RegisterServer2Response, configurationResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* AddNodesItem */ +static UA_DataTypeMember AddNodesItem_members[7] = { +{ + UA_TYPENAME("parentNodeId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("referenceTypeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_AddNodesItem, referenceTypeId) - offsetof(UA_AddNodesItem, parentNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedNewNodeId") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_AddNodesItem, requestedNewNodeId) - offsetof(UA_AddNodesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browseName") /* .memberName */ + UA_TYPES_QUALIFIEDNAME, /* .memberTypeIndex */ + offsetof(UA_AddNodesItem, browseName) - offsetof(UA_AddNodesItem, requestedNewNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodeClass") /* .memberName */ + UA_TYPES_NODECLASS, /* .memberTypeIndex */ + offsetof(UA_AddNodesItem, nodeClass) - offsetof(UA_AddNodesItem, browseName) - sizeof(UA_QualifiedName), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodeAttributes") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_AddNodesItem, nodeAttributes) - offsetof(UA_AddNodesItem, nodeClass) - sizeof(UA_NodeClass), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("typeDefinition") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + offsetof(UA_AddNodesItem, typeDefinition) - offsetof(UA_AddNodesItem, nodeAttributes) - sizeof(UA_ExtensionObject), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* NodeTypeDescription */ +static UA_DataTypeMember NodeTypeDescription_members[3] = { +{ + UA_TYPENAME("typeDefinitionNode") /* .memberName */ + UA_TYPES_EXPANDEDNODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("includeSubTypes") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_NodeTypeDescription, includeSubTypes) - offsetof(UA_NodeTypeDescription, typeDefinitionNode) - sizeof(UA_ExpandedNodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("dataToReturn") /* .memberName */ + UA_TYPES_QUERYDATADESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_NodeTypeDescription, dataToReturnSize) - offsetof(UA_NodeTypeDescription, includeSubTypes) - sizeof(UA_Boolean), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ServerStatusDataType */ +static UA_DataTypeMember ServerStatusDataType_members[6] = { +{ + UA_TYPENAME("startTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_ServerStatusDataType, currentTime) - offsetof(UA_ServerStatusDataType, startTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("state") /* .memberName */ + UA_TYPES_SERVERSTATE, /* .memberTypeIndex */ + offsetof(UA_ServerStatusDataType, state) - offsetof(UA_ServerStatusDataType, currentTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("buildInfo") /* .memberName */ + UA_TYPES_BUILDINFO, /* .memberTypeIndex */ + offsetof(UA_ServerStatusDataType, buildInfo) - offsetof(UA_ServerStatusDataType, state) - sizeof(UA_ServerState), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("secondsTillShutdown") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_ServerStatusDataType, secondsTillShutdown) - offsetof(UA_ServerStatusDataType, buildInfo) - sizeof(UA_BuildInfo), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("shutdownReason") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ServerStatusDataType, shutdownReason) - offsetof(UA_ServerStatusDataType, secondsTillShutdown) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AttributeOperand */ +static UA_DataTypeMember AttributeOperand_members[5] = { +{ + UA_TYPENAME("nodeId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("alias") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_AttributeOperand, alias) - offsetof(UA_AttributeOperand, nodeId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browsePath") /* .memberName */ + UA_TYPES_RELATIVEPATH, /* .memberTypeIndex */ + offsetof(UA_AttributeOperand, browsePath) - offsetof(UA_AttributeOperand, alias) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("attributeId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_AttributeOperand, attributeId) - offsetof(UA_AttributeOperand, browsePath) - sizeof(UA_RelativePath), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("indexRange") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_AttributeOperand, indexRange) - offsetof(UA_AttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AddReferencesResponse */ +static UA_DataTypeMember AddReferencesResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + offsetof(UA_AddReferencesResponse, resultsSize) - offsetof(UA_AddReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_AddReferencesResponse, diagnosticInfosSize) - offsetof(UA_AddReferencesResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* EventFilterResult */ +static UA_DataTypeMember EventFilterResult_members[3] = { +{ + UA_TYPENAME("selectClauseResults") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("selectClauseDiagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_EventFilterResult, selectClauseDiagnosticInfosSize) - offsetof(UA_EventFilterResult, selectClauseResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("whereClauseResult") /* .memberName */ + UA_TYPES_CONTENTFILTERRESULT, /* .memberTypeIndex */ + offsetof(UA_EventFilterResult, whereClauseResult) - offsetof(UA_EventFilterResult, selectClauseDiagnosticInfos) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* TranslateBrowsePathsToNodeIdsResponse */ +static UA_DataTypeMember TranslateBrowsePathsToNodeIdsResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_BROWSEPATHRESULT, /* .memberTypeIndex */ + offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, resultsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, diagnosticInfosSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* DataChangeFilter */ +static UA_DataTypeMember DataChangeFilter_members[3] = { +{ + UA_TYPENAME("trigger") /* .memberName */ + UA_TYPES_DATACHANGETRIGGER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deadbandType") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_DataChangeFilter, deadbandType) - offsetof(UA_DataChangeFilter, trigger) - sizeof(UA_DataChangeTrigger), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deadbandValue") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_DataChangeFilter, deadbandValue) - offsetof(UA_DataChangeFilter, deadbandType) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ContentFilterElement */ +static UA_DataTypeMember ContentFilterElement_members[2] = { +{ + UA_TYPENAME("filterOperator") /* .memberName */ + UA_TYPES_FILTEROPERATOR, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("filterOperands") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_ContentFilterElement, filterOperandsSize) - offsetof(UA_ContentFilterElement, filterOperator) - sizeof(UA_FilterOperator), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* TranslateBrowsePathsToNodeIdsRequest */ +static UA_DataTypeMember TranslateBrowsePathsToNodeIdsRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browsePaths") /* .memberName */ + UA_TYPES_BROWSEPATH, /* .memberTypeIndex */ + offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, browsePathsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CloseSessionResponse */ +static UA_DataTypeMember CloseSessionResponse_members[1] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ApplicationDescription */ +static UA_DataTypeMember ApplicationDescription_members[7] = { +{ + UA_TYPENAME("applicationUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("productUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ApplicationDescription, productUri) - offsetof(UA_ApplicationDescription, applicationUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("applicationName") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_ApplicationDescription, applicationName) - offsetof(UA_ApplicationDescription, productUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("applicationType") /* .memberName */ + UA_TYPES_APPLICATIONTYPE, /* .memberTypeIndex */ + offsetof(UA_ApplicationDescription, applicationType) - offsetof(UA_ApplicationDescription, applicationName) - sizeof(UA_LocalizedText), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("gatewayServerUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ApplicationDescription, gatewayServerUri) - offsetof(UA_ApplicationDescription, applicationType) - sizeof(UA_ApplicationType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discoveryProfileUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ApplicationDescription, discoveryProfileUri) - offsetof(UA_ApplicationDescription, gatewayServerUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discoveryUrls") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_ApplicationDescription, discoveryUrlsSize) - offsetof(UA_ApplicationDescription, discoveryProfileUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* SessionDiagnosticsDataType */ +static UA_DataTypeMember SessionDiagnosticsDataType_members[43] = { +{ + UA_TYPENAME("sessionId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sessionName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, sessionName) - offsetof(UA_SessionDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientDescription") /* .memberName */ + UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, clientDescription) - offsetof(UA_SessionDiagnosticsDataType, sessionName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, serverUri) - offsetof(UA_SessionDiagnosticsDataType, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("endpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, endpointUrl) - offsetof(UA_SessionDiagnosticsDataType, serverUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("localeIds") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, localeIdsSize) - offsetof(UA_SessionDiagnosticsDataType, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("actualSessionTimeout") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, actualSessionTimeout) - offsetof(UA_SessionDiagnosticsDataType, localeIds) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxResponseMessageSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, maxResponseMessageSize) - offsetof(UA_SessionDiagnosticsDataType, actualSessionTimeout) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientConnectionTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, clientConnectionTime) - offsetof(UA_SessionDiagnosticsDataType, maxResponseMessageSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientLastContactTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, clientLastContactTime) - offsetof(UA_SessionDiagnosticsDataType, clientConnectionTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentSubscriptionsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, currentSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, clientLastContactTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentMonitoredItemsCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, currentMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, currentSubscriptionsCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("currentPublishRequestsInQueue") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, currentPublishRequestsInQueue) - offsetof(UA_SessionDiagnosticsDataType, currentMonitoredItemsCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("totalRequestCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, totalRequestCount) - offsetof(UA_SessionDiagnosticsDataType, currentPublishRequestsInQueue) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("unauthorizedRequestCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, unauthorizedRequestCount) - offsetof(UA_SessionDiagnosticsDataType, totalRequestCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("readCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, readCount) - offsetof(UA_SessionDiagnosticsDataType, unauthorizedRequestCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("historyReadCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, historyReadCount) - offsetof(UA_SessionDiagnosticsDataType, readCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("writeCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, writeCount) - offsetof(UA_SessionDiagnosticsDataType, historyReadCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("historyUpdateCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, historyUpdateCount) - offsetof(UA_SessionDiagnosticsDataType, writeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("callCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, callCount) - offsetof(UA_SessionDiagnosticsDataType, historyUpdateCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("createMonitoredItemsCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, createMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, callCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("modifyMonitoredItemsCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, modifyMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, createMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("setMonitoringModeCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, setMonitoringModeCount) - offsetof(UA_SessionDiagnosticsDataType, modifyMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("setTriggeringCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, setTriggeringCount) - offsetof(UA_SessionDiagnosticsDataType, setMonitoringModeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteMonitoredItemsCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, deleteMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, setTriggeringCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("createSubscriptionCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, createSubscriptionCount) - offsetof(UA_SessionDiagnosticsDataType, deleteMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("modifySubscriptionCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, modifySubscriptionCount) - offsetof(UA_SessionDiagnosticsDataType, createSubscriptionCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("setPublishingModeCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, setPublishingModeCount) - offsetof(UA_SessionDiagnosticsDataType, modifySubscriptionCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("publishCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, publishCount) - offsetof(UA_SessionDiagnosticsDataType, setPublishingModeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("republishCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, republishCount) - offsetof(UA_SessionDiagnosticsDataType, publishCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("transferSubscriptionsCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, transferSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, republishCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteSubscriptionsCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, deleteSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, transferSubscriptionsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("addNodesCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, addNodesCount) - offsetof(UA_SessionDiagnosticsDataType, deleteSubscriptionsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("addReferencesCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, addReferencesCount) - offsetof(UA_SessionDiagnosticsDataType, addNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteNodesCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, deleteNodesCount) - offsetof(UA_SessionDiagnosticsDataType, addReferencesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("deleteReferencesCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, deleteReferencesCount) - offsetof(UA_SessionDiagnosticsDataType, deleteNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browseCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, browseCount) - offsetof(UA_SessionDiagnosticsDataType, deleteReferencesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("browseNextCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, browseNextCount) - offsetof(UA_SessionDiagnosticsDataType, browseCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("translateBrowsePathsToNodeIdsCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, translateBrowsePathsToNodeIdsCount) - offsetof(UA_SessionDiagnosticsDataType, browseNextCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("queryFirstCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, queryFirstCount) - offsetof(UA_SessionDiagnosticsDataType, translateBrowsePathsToNodeIdsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("queryNextCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, queryNextCount) - offsetof(UA_SessionDiagnosticsDataType, queryFirstCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("registerNodesCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, registerNodesCount) - offsetof(UA_SessionDiagnosticsDataType, queryNextCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("unregisterNodesCount") /* .memberName */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .memberTypeIndex */ + offsetof(UA_SessionDiagnosticsDataType, unregisterNodesCount) - offsetof(UA_SessionDiagnosticsDataType, registerNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ServiceFault */ +static UA_DataTypeMember ServiceFault_members[1] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RegisteredServer */ +static UA_DataTypeMember RegisteredServer_members[8] = { +{ + UA_TYPENAME("serverUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("productUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, productUri) - offsetof(UA_RegisteredServer, serverUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverNames") /* .memberName */ + UA_TYPES_LOCALIZEDTEXT, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, serverNamesSize) - offsetof(UA_RegisteredServer, productUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("serverType") /* .memberName */ + UA_TYPES_APPLICATIONTYPE, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, serverType) - offsetof(UA_RegisteredServer, serverNames) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("gatewayServerUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, gatewayServerUri) - offsetof(UA_RegisteredServer, serverType) - sizeof(UA_ApplicationType), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discoveryUrls") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, discoveryUrlsSize) - offsetof(UA_RegisteredServer, gatewayServerUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("semaphoreFilePath") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, semaphoreFilePath) - offsetof(UA_RegisteredServer, discoveryUrls) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("isOnline") /* .memberName */ + UA_TYPES_BOOLEAN, /* .memberTypeIndex */ + offsetof(UA_RegisteredServer, isOnline) - offsetof(UA_RegisteredServer, semaphoreFilePath) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AggregateFilter */ +static UA_DataTypeMember AggregateFilter_members[4] = { +{ + UA_TYPENAME("startTime") /* .memberName */ + UA_TYPES_DATETIME, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("aggregateType") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_AggregateFilter, aggregateType) - offsetof(UA_AggregateFilter, startTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("processingInterval") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_AggregateFilter, processingInterval) - offsetof(UA_AggregateFilter, aggregateType) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("aggregateConfiguration") /* .memberName */ + UA_TYPES_AGGREGATECONFIGURATION, /* .memberTypeIndex */ + offsetof(UA_AggregateFilter, aggregateConfiguration) - offsetof(UA_AggregateFilter, processingInterval) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* RegisterServerRequest */ +static UA_DataTypeMember RegisterServerRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("server") /* .memberName */ + UA_TYPES_REGISTEREDSERVER, /* .memberTypeIndex */ + offsetof(UA_RegisterServerRequest, server) - offsetof(UA_RegisterServerRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* EndpointDescription */ +static UA_DataTypeMember EndpointDescription_members[8] = { +{ + UA_TYPENAME("endpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("server") /* .memberName */ + UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, server) - offsetof(UA_EndpointDescription, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverCertificate") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, serverCertificate) - offsetof(UA_EndpointDescription, server) - sizeof(UA_ApplicationDescription), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityMode") /* .memberName */ + UA_TYPES_MESSAGESECURITYMODE, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, securityMode) - offsetof(UA_EndpointDescription, serverCertificate) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityPolicyUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, securityPolicyUri) - offsetof(UA_EndpointDescription, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("userIdentityTokens") /* .memberName */ + UA_TYPES_USERTOKENPOLICY, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, userIdentityTokensSize) - offsetof(UA_EndpointDescription, securityPolicyUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("transportProfileUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, transportProfileUri) - offsetof(UA_EndpointDescription, userIdentityTokens) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("securityLevel") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_EndpointDescription, securityLevel) - offsetof(UA_EndpointDescription, transportProfileUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* CreateMonitoredItemsRequest */ +static UA_DataTypeMember CreateMonitoredItemsRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("subscriptionId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - offsetof(UA_CreateMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("timestampsToReturn") /* .memberName */ + UA_TYPES_TIMESTAMPSTORETURN, /* .memberTypeIndex */ + offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("itemsToCreate") /* .memberName */ + UA_TYPES_MONITOREDITEMCREATEREQUEST, /* .memberTypeIndex */ + offsetof(UA_CreateMonitoredItemsRequest, itemsToCreateSize) - offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* ContentFilter */ +static UA_DataTypeMember ContentFilter_members[1] = { +{ + UA_TYPENAME("elements") /* .memberName */ + UA_TYPES_CONTENTFILTERELEMENT, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* QueryFirstResponse */ +static UA_DataTypeMember QueryFirstResponse_members[6] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("queryDataSets") /* .memberName */ + UA_TYPES_QUERYDATASET, /* .memberTypeIndex */ + offsetof(UA_QueryFirstResponse, queryDataSetsSize) - offsetof(UA_QueryFirstResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("continuationPoint") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_QueryFirstResponse, continuationPoint) - offsetof(UA_QueryFirstResponse, queryDataSets) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("parsingResults") /* .memberName */ + UA_TYPES_PARSINGRESULT, /* .memberTypeIndex */ + offsetof(UA_QueryFirstResponse, parsingResultsSize) - offsetof(UA_QueryFirstResponse, continuationPoint) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_QueryFirstResponse, diagnosticInfosSize) - offsetof(UA_QueryFirstResponse, parsingResults) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("filterResult") /* .memberName */ + UA_TYPES_CONTENTFILTERRESULT, /* .memberTypeIndex */ + offsetof(UA_QueryFirstResponse, filterResult) - offsetof(UA_QueryFirstResponse, diagnosticInfos) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AddNodesRequest */ +static UA_DataTypeMember AddNodesRequest_members[2] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToAdd") /* .memberName */ + UA_TYPES_ADDNODESITEM, /* .memberTypeIndex */ + offsetof(UA_AddNodesRequest, nodesToAddSize) - offsetof(UA_AddNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* BrowseRequest */ +static UA_DataTypeMember BrowseRequest_members[4] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("view") /* .memberName */ + UA_TYPES_VIEWDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_BrowseRequest, view) - offsetof(UA_BrowseRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedMaxReferencesPerNode") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - offsetof(UA_BrowseRequest, view) - sizeof(UA_ViewDescription), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodesToBrowse") /* .memberName */ + UA_TYPES_BROWSEDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_BrowseRequest, nodesToBrowseSize) - offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* BrowseResult */ +static UA_DataTypeMember BrowseResult_members[3] = { +{ + UA_TYPENAME("statusCode") /* .memberName */ + UA_TYPES_STATUSCODE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("continuationPoint") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_BrowseResult, continuationPoint) - offsetof(UA_BrowseResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("references") /* .memberName */ + UA_TYPES_REFERENCEDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_BrowseResult, referencesSize) - offsetof(UA_BrowseResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* RegisterServer2Request */ +static UA_DataTypeMember RegisterServer2Request_members[3] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("server") /* .memberName */ + UA_TYPES_REGISTEREDSERVER, /* .memberTypeIndex */ + offsetof(UA_RegisterServer2Request, server) - offsetof(UA_RegisterServer2Request, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("discoveryConfiguration") /* .memberName */ + UA_TYPES_EXTENSIONOBJECT, /* .memberTypeIndex */ + offsetof(UA_RegisterServer2Request, discoveryConfigurationSize) - offsetof(UA_RegisterServer2Request, server) - sizeof(UA_RegisteredServer), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CreateSessionRequest */ +static UA_DataTypeMember CreateSessionRequest_members[9] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientDescription") /* .memberName */ + UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, clientDescription) - offsetof(UA_CreateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverUri") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, serverUri) - offsetof(UA_CreateSessionRequest, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("endpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, endpointUrl) - offsetof(UA_CreateSessionRequest, serverUri) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sessionName") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, sessionName) - offsetof(UA_CreateSessionRequest, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientNonce") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, clientNonce) - offsetof(UA_CreateSessionRequest, sessionName) - sizeof(UA_String), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("clientCertificate") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, clientCertificate) - offsetof(UA_CreateSessionRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestedSessionTimeout") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - offsetof(UA_CreateSessionRequest, clientCertificate) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxResponseMessageSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSessionRequest, maxResponseMessageSize) - offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* EventFilter */ +static UA_DataTypeMember EventFilter_members[2] = { +{ + UA_TYPENAME("selectClauses") /* .memberName */ + UA_TYPES_SIMPLEATTRIBUTEOPERAND, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("whereClause") /* .memberName */ + UA_TYPES_CONTENTFILTER, /* .memberTypeIndex */ + offsetof(UA_EventFilter, whereClause) - offsetof(UA_EventFilter, selectClauses) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* GetEndpointsResponse */ +static UA_DataTypeMember GetEndpointsResponse_members[2] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("endpoints") /* .memberName */ + UA_TYPES_ENDPOINTDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_GetEndpointsResponse, endpointsSize) - offsetof(UA_GetEndpointsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* FindServersResponse */ +static UA_DataTypeMember FindServersResponse_members[2] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("servers") /* .memberName */ + UA_TYPES_APPLICATIONDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_FindServersResponse, serversSize) - offsetof(UA_FindServersResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* BrowseNextResponse */ +static UA_DataTypeMember BrowseNextResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_BROWSERESULT, /* .memberTypeIndex */ + offsetof(UA_BrowseNextResponse, resultsSize) - offsetof(UA_BrowseNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_BrowseNextResponse, diagnosticInfosSize) - offsetof(UA_BrowseNextResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* BrowseResponse */ +static UA_DataTypeMember BrowseResponse_members[3] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("results") /* .memberName */ + UA_TYPES_BROWSERESULT, /* .memberTypeIndex */ + offsetof(UA_BrowseResponse, resultsSize) - offsetof(UA_BrowseResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("diagnosticInfos") /* .memberName */ + UA_TYPES_DIAGNOSTICINFO, /* .memberTypeIndex */ + offsetof(UA_BrowseResponse, diagnosticInfosSize) - offsetof(UA_BrowseResponse, results) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}}; + +/* CreateSessionResponse */ +static UA_DataTypeMember CreateSessionResponse_members[10] = { +{ + UA_TYPENAME("responseHeader") /* .memberName */ + UA_TYPES_RESPONSEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sessionId") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, sessionId) - offsetof(UA_CreateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("authenticationToken") /* .memberName */ + UA_TYPES_NODEID, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, authenticationToken) - offsetof(UA_CreateSessionResponse, sessionId) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("revisedSessionTimeout") /* .memberName */ + UA_TYPES_DOUBLE, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - offsetof(UA_CreateSessionResponse, authenticationToken) - sizeof(UA_NodeId), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverNonce") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, serverNonce) - offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - sizeof(UA_Double), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverCertificate") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, serverCertificate) - offsetof(UA_CreateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("serverEndpoints") /* .memberName */ + UA_TYPES_ENDPOINTDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, serverEndpointsSize) - offsetof(UA_CreateSessionResponse, serverCertificate) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("serverSoftwareCertificates") /* .memberName */ + UA_TYPES_SIGNEDSOFTWARECERTIFICATE, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, serverSoftwareCertificatesSize) - offsetof(UA_CreateSessionResponse, serverEndpoints) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("serverSignature") /* .memberName */ + UA_TYPES_SIGNATUREDATA, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, serverSignature) - offsetof(UA_CreateSessionResponse, serverSoftwareCertificates) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxRequestMessageSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_CreateSessionResponse, maxRequestMessageSize) - offsetof(UA_CreateSessionResponse, serverSignature) - sizeof(UA_SignatureData), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* QueryFirstRequest */ +static UA_DataTypeMember QueryFirstRequest_members[6] = { +{ + UA_TYPENAME("requestHeader") /* .memberName */ + UA_TYPES_REQUESTHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("view") /* .memberName */ + UA_TYPES_VIEWDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_QueryFirstRequest, view) - offsetof(UA_QueryFirstRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("nodeTypes") /* .memberName */ + UA_TYPES_NODETYPEDESCRIPTION, /* .memberTypeIndex */ + offsetof(UA_QueryFirstRequest, nodeTypesSize) - offsetof(UA_QueryFirstRequest, view) - sizeof(UA_ViewDescription), /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("filter") /* .memberName */ + UA_TYPES_CONTENTFILTER, /* .memberTypeIndex */ + offsetof(UA_QueryFirstRequest, filter) - offsetof(UA_QueryFirstRequest, nodeTypes) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxDataSetsToReturn") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_QueryFirstRequest, maxDataSetsToReturn) - offsetof(UA_QueryFirstRequest, filter) - sizeof(UA_ContentFilter), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxReferencesToReturn") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_QueryFirstRequest, maxReferencesToReturn) - offsetof(UA_QueryFirstRequest, maxDataSetsToReturn) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; +const UA_DataType UA_TYPES[UA_TYPES_COUNT] = { +/* Boolean */ +{ + UA_TYPENAME("Boolean") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {1}}, /* .typeId */ + sizeof(UA_Boolean), /* .memSize */ + UA_TYPES_BOOLEAN, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + true, /* .overlayable */ + 0, /* .binaryEncodingId */ + Boolean_members /* .members */ +}, +/* SByte */ +{ + UA_TYPENAME("SByte") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {2}}, /* .typeId */ + sizeof(UA_SByte), /* .memSize */ + UA_TYPES_SBYTE, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + true, /* .overlayable */ + 0, /* .binaryEncodingId */ + SByte_members /* .members */ +}, +/* Byte */ +{ + UA_TYPENAME("Byte") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {3}}, /* .typeId */ + sizeof(UA_Byte), /* .memSize */ + UA_TYPES_BYTE, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + true, /* .overlayable */ + 0, /* .binaryEncodingId */ + Byte_members /* .members */ +}, +/* Int16 */ +{ + UA_TYPENAME("Int16") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {4}}, /* .typeId */ + sizeof(UA_Int16), /* .memSize */ + UA_TYPES_INT16, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + Int16_members /* .members */ +}, +/* UInt16 */ +{ + UA_TYPENAME("UInt16") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {5}}, /* .typeId */ + sizeof(UA_UInt16), /* .memSize */ + UA_TYPES_UINT16, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + UInt16_members /* .members */ +}, +/* Int32 */ +{ + UA_TYPENAME("Int32") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {6}}, /* .typeId */ + sizeof(UA_Int32), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + Int32_members /* .members */ +}, +/* UInt32 */ +{ + UA_TYPENAME("UInt32") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {7}}, /* .typeId */ + sizeof(UA_UInt32), /* .memSize */ + UA_TYPES_UINT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + UInt32_members /* .members */ +}, +/* Int64 */ +{ + UA_TYPENAME("Int64") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {8}}, /* .typeId */ + sizeof(UA_Int64), /* .memSize */ + UA_TYPES_INT64, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + Int64_members /* .members */ +}, +/* UInt64 */ +{ + UA_TYPENAME("UInt64") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {9}}, /* .typeId */ + sizeof(UA_UInt64), /* .memSize */ + UA_TYPES_UINT64, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + UInt64_members /* .members */ +}, +/* Float */ +{ + UA_TYPENAME("Float") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {10}}, /* .typeId */ + sizeof(UA_Float), /* .memSize */ + UA_TYPES_FLOAT, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */ + 0, /* .binaryEncodingId */ + Float_members /* .members */ +}, +/* Double */ +{ + UA_TYPENAME("Double") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {11}}, /* .typeId */ + sizeof(UA_Double), /* .memSize */ + UA_TYPES_DOUBLE, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */ + 0, /* .binaryEncodingId */ + Double_members /* .members */ +}, +/* String */ +{ + UA_TYPENAME("String") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12}}, /* .typeId */ + sizeof(UA_String), /* .memSize */ + UA_TYPES_STRING, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + String_members /* .members */ +}, +/* DateTime */ +{ + UA_TYPENAME("DateTime") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {13}}, /* .typeId */ + sizeof(UA_DateTime), /* .memSize */ + UA_TYPES_DATETIME, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + DateTime_members /* .members */ +}, +/* Guid */ +{ + UA_TYPENAME("Guid") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {14}}, /* .typeId */ + sizeof(UA_Guid), /* .memSize */ + UA_TYPES_GUID, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + 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, /* .binaryEncodingId */ + Guid_members /* .members */ +}, +/* ByteString */ +{ + UA_TYPENAME("ByteString") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {15}}, /* .typeId */ + sizeof(UA_ByteString), /* .memSize */ + UA_TYPES_BYTESTRING, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + ByteString_members /* .members */ +}, +/* XmlElement */ +{ + UA_TYPENAME("XmlElement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {16}}, /* .typeId */ + sizeof(UA_XmlElement), /* .memSize */ + UA_TYPES_XMLELEMENT, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + XmlElement_members /* .members */ +}, +/* NodeId */ +{ + UA_TYPENAME("NodeId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {17}}, /* .typeId */ + sizeof(UA_NodeId), /* .memSize */ + UA_TYPES_NODEID, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + NodeId_members /* .members */ +}, +/* ExpandedNodeId */ +{ + UA_TYPENAME("ExpandedNodeId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {18}}, /* .typeId */ + sizeof(UA_ExpandedNodeId), /* .memSize */ + UA_TYPES_EXPANDEDNODEID, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + ExpandedNodeId_members /* .members */ +}, +/* StatusCode */ +{ + UA_TYPENAME("StatusCode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {19}}, /* .typeId */ + sizeof(UA_StatusCode), /* .memSize */ + UA_TYPES_STATUSCODE, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + StatusCode_members /* .members */ +}, +/* QualifiedName */ +{ + UA_TYPENAME("QualifiedName") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {20}}, /* .typeId */ + sizeof(UA_QualifiedName), /* .memSize */ + UA_TYPES_QUALIFIEDNAME, /* .typeIndex */ + 2, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + QualifiedName_members /* .members */ +}, +/* LocalizedText */ +{ + UA_TYPENAME("LocalizedText") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {21}}, /* .typeId */ + sizeof(UA_LocalizedText), /* .memSize */ + UA_TYPES_LOCALIZEDTEXT, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + LocalizedText_members /* .members */ +}, +/* ExtensionObject */ +{ + UA_TYPENAME("ExtensionObject") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {22}}, /* .typeId */ + sizeof(UA_ExtensionObject), /* .memSize */ + UA_TYPES_EXTENSIONOBJECT, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + ExtensionObject_members /* .members */ +}, +/* DataValue */ +{ + UA_TYPENAME("DataValue") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {23}}, /* .typeId */ + sizeof(UA_DataValue), /* .memSize */ + UA_TYPES_DATAVALUE, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + DataValue_members /* .members */ +}, +/* Variant */ +{ + UA_TYPENAME("Variant") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {24}}, /* .typeId */ + sizeof(UA_Variant), /* .memSize */ + UA_TYPES_VARIANT, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + Variant_members /* .members */ +}, +/* DiagnosticInfo */ +{ + UA_TYPENAME("DiagnosticInfo") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {25}}, /* .typeId */ + sizeof(UA_DiagnosticInfo), /* .memSize */ + UA_TYPES_DIAGNOSTICINFO, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + DiagnosticInfo_members /* .members */ +}, +/* SignedSoftwareCertificate */ +{ + UA_TYPENAME("SignedSoftwareCertificate") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {344}}, /* .typeId */ + sizeof(UA_SignedSoftwareCertificate), /* .memSize */ + UA_TYPES_SIGNEDSOFTWARECERTIFICATE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 346, /* .binaryEncodingId */ + SignedSoftwareCertificate_members /* .members */ +}, +/* SemanticChangeStructureDataType */ +{ + UA_TYPENAME("SemanticChangeStructureDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {897}}, /* .typeId */ + sizeof(UA_SemanticChangeStructureDataType), /* .memSize */ + UA_TYPES_SEMANTICCHANGESTRUCTUREDATATYPE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 899, /* .binaryEncodingId */ + SemanticChangeStructureDataType_members /* .members */ +}, +/* StatusChangeNotification */ +{ + UA_TYPENAME("StatusChangeNotification") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {818}}, /* .typeId */ + sizeof(UA_StatusChangeNotification), /* .memSize */ + UA_TYPES_STATUSCHANGENOTIFICATION, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 820, /* .binaryEncodingId */ + StatusChangeNotification_members /* .members */ +}, +/* BrowsePathTarget */ +{ + UA_TYPENAME("BrowsePathTarget") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {546}}, /* .typeId */ + sizeof(UA_BrowsePathTarget), /* .memSize */ + UA_TYPES_BROWSEPATHTARGET, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 548, /* .binaryEncodingId */ + BrowsePathTarget_members /* .members */ +}, +/* ViewAttributes */ +{ + UA_TYPENAME("ViewAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {373}}, /* .typeId */ + sizeof(UA_ViewAttributes), /* .memSize */ + UA_TYPES_VIEWATTRIBUTES, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 375, /* .binaryEncodingId */ + ViewAttributes_members /* .members */ +}, +/* RequestHeader */ +{ + UA_TYPENAME("RequestHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {389}}, /* .typeId */ + sizeof(UA_RequestHeader), /* .memSize */ + UA_TYPES_REQUESTHEADER, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 391, /* .binaryEncodingId */ + RequestHeader_members /* .members */ +}, +/* MonitoredItemModifyResult */ +{ + UA_TYPENAME("MonitoredItemModifyResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {758}}, /* .typeId */ + sizeof(UA_MonitoredItemModifyResult), /* .memSize */ + UA_TYPES_MONITOREDITEMMODIFYRESULT, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 760, /* .binaryEncodingId */ + MonitoredItemModifyResult_members /* .members */ +}, +/* ElementOperand */ +{ + UA_TYPENAME("ElementOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {592}}, /* .typeId */ + sizeof(UA_ElementOperand), /* .memSize */ + UA_TYPES_ELEMENTOPERAND, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 594, /* .binaryEncodingId */ + ElementOperand_members /* .members */ +}, +/* CloseSecureChannelRequest */ +{ + UA_TYPENAME("CloseSecureChannelRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {450}}, /* .typeId */ + sizeof(UA_CloseSecureChannelRequest), /* .memSize */ + UA_TYPES_CLOSESECURECHANNELREQUEST, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 452, /* .binaryEncodingId */ + CloseSecureChannelRequest_members /* .members */ +}, +/* AddNodesResult */ +{ + UA_TYPENAME("AddNodesResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {483}}, /* .typeId */ + sizeof(UA_AddNodesResult), /* .memSize */ + UA_TYPES_ADDNODESRESULT, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 485, /* .binaryEncodingId */ + AddNodesResult_members /* .members */ +}, +/* VariableAttributes */ +{ + UA_TYPENAME("VariableAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {355}}, /* .typeId */ + sizeof(UA_VariableAttributes), /* .memSize */ + UA_TYPES_VARIABLEATTRIBUTES, /* .typeIndex */ + 13, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 357, /* .binaryEncodingId */ + VariableAttributes_members /* .members */ +}, +/* NotificationMessage */ +{ + UA_TYPENAME("NotificationMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {803}}, /* .typeId */ + sizeof(UA_NotificationMessage), /* .memSize */ + UA_TYPES_NOTIFICATIONMESSAGE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 805, /* .binaryEncodingId */ + NotificationMessage_members /* .members */ +}, +/* FindServersOnNetworkRequest */ +{ + UA_TYPENAME("FindServersOnNetworkRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12190}}, /* .typeId */ + sizeof(UA_FindServersOnNetworkRequest), /* .memSize */ + UA_TYPES_FINDSERVERSONNETWORKREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 12208, /* .binaryEncodingId */ + FindServersOnNetworkRequest_members /* .members */ +}, +/* EventFieldList */ +{ + UA_TYPENAME("EventFieldList") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {917}}, /* .typeId */ + sizeof(UA_EventFieldList), /* .memSize */ + UA_TYPES_EVENTFIELDLIST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 919, /* .binaryEncodingId */ + EventFieldList_members /* .members */ +}, +/* MonitoringMode */ +{ + UA_TYPENAME("MonitoringMode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {716}}, /* .typeId */ + sizeof(UA_MonitoringMode), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + MonitoringMode_members /* .members */ +}, +/* MdnsDiscoveryConfiguration */ +{ + UA_TYPENAME("MdnsDiscoveryConfiguration") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12891}}, /* .typeId */ + sizeof(UA_MdnsDiscoveryConfiguration), /* .memSize */ + UA_TYPES_MDNSDISCOVERYCONFIGURATION, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 12901, /* .binaryEncodingId */ + MdnsDiscoveryConfiguration_members /* .members */ +}, +/* CallMethodResult */ +{ + UA_TYPENAME("CallMethodResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {707}}, /* .typeId */ + sizeof(UA_CallMethodResult), /* .memSize */ + UA_TYPES_CALLMETHODRESULT, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 709, /* .binaryEncodingId */ + CallMethodResult_members /* .members */ +}, +/* ParsingResult */ +{ + UA_TYPENAME("ParsingResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {610}}, /* .typeId */ + sizeof(UA_ParsingResult), /* .memSize */ + UA_TYPES_PARSINGRESULT, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 612, /* .binaryEncodingId */ + ParsingResult_members /* .members */ +}, +/* RelativePathElement */ +{ + UA_TYPENAME("RelativePathElement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {537}}, /* .typeId */ + sizeof(UA_RelativePathElement), /* .memSize */ + UA_TYPES_RELATIVEPATHELEMENT, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 539, /* .binaryEncodingId */ + RelativePathElement_members /* .members */ +}, +/* BrowseDirection */ +{ + UA_TYPENAME("BrowseDirection") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {510}}, /* .typeId */ + sizeof(UA_BrowseDirection), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + BrowseDirection_members /* .members */ +}, +/* CallMethodRequest */ +{ + UA_TYPENAME("CallMethodRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {704}}, /* .typeId */ + sizeof(UA_CallMethodRequest), /* .memSize */ + UA_TYPES_CALLMETHODREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 706, /* .binaryEncodingId */ + CallMethodRequest_members /* .members */ +}, +/* RedundancySupport */ +{ + UA_TYPENAME("RedundancySupport") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {851}}, /* .typeId */ + sizeof(UA_RedundancySupport), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + RedundancySupport_members /* .members */ +}, +/* EventNotificationList */ +{ + UA_TYPENAME("EventNotificationList") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {914}}, /* .typeId */ + sizeof(UA_EventNotificationList), /* .memSize */ + UA_TYPES_EVENTNOTIFICATIONLIST, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 916, /* .binaryEncodingId */ + EventNotificationList_members /* .members */ +}, +/* UnregisterNodesRequest */ +{ + UA_TYPENAME("UnregisterNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {564}}, /* .typeId */ + sizeof(UA_UnregisterNodesRequest), /* .memSize */ + UA_TYPES_UNREGISTERNODESREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 566, /* .binaryEncodingId */ + UnregisterNodesRequest_members /* .members */ +}, +/* ContentFilterElementResult */ +{ + UA_TYPENAME("ContentFilterElementResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {604}}, /* .typeId */ + sizeof(UA_ContentFilterElementResult), /* .memSize */ + UA_TYPES_CONTENTFILTERELEMENTRESULT, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 606, /* .binaryEncodingId */ + ContentFilterElementResult_members /* .members */ +}, +/* SimpleAttributeOperand */ +{ + UA_TYPENAME("SimpleAttributeOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {601}}, /* .typeId */ + sizeof(UA_SimpleAttributeOperand), /* .memSize */ + UA_TYPES_SIMPLEATTRIBUTEOPERAND, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 603, /* .binaryEncodingId */ + SimpleAttributeOperand_members /* .members */ +}, +/* LiteralOperand */ +{ + UA_TYPENAME("LiteralOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {595}}, /* .typeId */ + sizeof(UA_LiteralOperand), /* .memSize */ + UA_TYPES_LITERALOPERAND, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 597, /* .binaryEncodingId */ + LiteralOperand_members /* .members */ +}, +/* QueryDataSet */ +{ + UA_TYPENAME("QueryDataSet") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {577}}, /* .typeId */ + sizeof(UA_QueryDataSet), /* .memSize */ + UA_TYPES_QUERYDATASET, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 579, /* .binaryEncodingId */ + QueryDataSet_members /* .members */ +}, +/* AnonymousIdentityToken */ +{ + UA_TYPENAME("AnonymousIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {319}}, /* .typeId */ + sizeof(UA_AnonymousIdentityToken), /* .memSize */ + UA_TYPES_ANONYMOUSIDENTITYTOKEN, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 321, /* .binaryEncodingId */ + AnonymousIdentityToken_members /* .members */ +}, +/* SetPublishingModeRequest */ +{ + UA_TYPENAME("SetPublishingModeRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {797}}, /* .typeId */ + sizeof(UA_SetPublishingModeRequest), /* .memSize */ + UA_TYPES_SETPUBLISHINGMODEREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 799, /* .binaryEncodingId */ + SetPublishingModeRequest_members /* .members */ +}, +/* MonitoredItemCreateResult */ +{ + UA_TYPENAME("MonitoredItemCreateResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {746}}, /* .typeId */ + sizeof(UA_MonitoredItemCreateResult), /* .memSize */ + UA_TYPES_MONITOREDITEMCREATERESULT, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 748, /* .binaryEncodingId */ + MonitoredItemCreateResult_members /* .members */ +}, +/* TimestampsToReturn */ +{ + UA_TYPENAME("TimestampsToReturn") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {625}}, /* .typeId */ + sizeof(UA_TimestampsToReturn), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + TimestampsToReturn_members /* .members */ +}, +/* CallRequest */ +{ + UA_TYPENAME("CallRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {710}}, /* .typeId */ + sizeof(UA_CallRequest), /* .memSize */ + UA_TYPES_CALLREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 712, /* .binaryEncodingId */ + CallRequest_members /* .members */ +}, +/* MethodAttributes */ +{ + UA_TYPENAME("MethodAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {358}}, /* .typeId */ + sizeof(UA_MethodAttributes), /* .memSize */ + UA_TYPES_METHODATTRIBUTES, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 360, /* .binaryEncodingId */ + MethodAttributes_members /* .members */ +}, +/* DeleteReferencesItem */ +{ + UA_TYPENAME("DeleteReferencesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {385}}, /* .typeId */ + sizeof(UA_DeleteReferencesItem), /* .memSize */ + UA_TYPES_DELETEREFERENCESITEM, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 387, /* .binaryEncodingId */ + DeleteReferencesItem_members /* .members */ +}, +/* WriteValue */ +{ + UA_TYPENAME("WriteValue") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {668}}, /* .typeId */ + sizeof(UA_WriteValue), /* .memSize */ + UA_TYPES_WRITEVALUE, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 670, /* .binaryEncodingId */ + WriteValue_members /* .members */ +}, +/* NodeAttributesMask */ +{ + UA_TYPENAME("NodeAttributesMask") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {348}}, /* .typeId */ + sizeof(UA_NodeAttributesMask), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + NodeAttributesMask_members /* .members */ +}, +/* MessageSecurityMode */ +{ + UA_TYPENAME("MessageSecurityMode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {302}}, /* .typeId */ + sizeof(UA_MessageSecurityMode), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + MessageSecurityMode_members /* .members */ +}, +/* MonitoringParameters */ +{ + UA_TYPENAME("MonitoringParameters") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {740}}, /* .typeId */ + sizeof(UA_MonitoringParameters), /* .memSize */ + UA_TYPES_MONITORINGPARAMETERS, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 742, /* .binaryEncodingId */ + MonitoringParameters_members /* .members */ +}, +/* ReferenceNode */ +{ + UA_TYPENAME("ReferenceNode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {285}}, /* .typeId */ + sizeof(UA_ReferenceNode), /* .memSize */ + UA_TYPES_REFERENCENODE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 287, /* .binaryEncodingId */ + ReferenceNode_members /* .members */ +}, +/* Argument */ +{ + UA_TYPENAME("Argument") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {296}}, /* .typeId */ + sizeof(UA_Argument), /* .memSize */ + UA_TYPES_ARGUMENT, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 298, /* .binaryEncodingId */ + Argument_members /* .members */ +}, +/* ChannelSecurityToken */ +{ + UA_TYPENAME("ChannelSecurityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {441}}, /* .typeId */ + sizeof(UA_ChannelSecurityToken), /* .memSize */ + UA_TYPES_CHANNELSECURITYTOKEN, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ChannelSecurityToken, tokenId) == (offsetof(UA_ChannelSecurityToken, channelId) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ChannelSecurityToken, createdAt) == (offsetof(UA_ChannelSecurityToken, tokenId) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ChannelSecurityToken, revisedLifetime) == (offsetof(UA_ChannelSecurityToken, createdAt) + sizeof(UA_DateTime)), /* .overlayable */ + 443, /* .binaryEncodingId */ + ChannelSecurityToken_members /* .members */ +}, +/* UserIdentityToken */ +{ + UA_TYPENAME("UserIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {316}}, /* .typeId */ + sizeof(UA_UserIdentityToken), /* .memSize */ + UA_TYPES_USERIDENTITYTOKEN, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 318, /* .binaryEncodingId */ + UserIdentityToken_members /* .members */ +}, +/* SignatureData */ +{ + UA_TYPENAME("SignatureData") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {456}}, /* .typeId */ + sizeof(UA_SignatureData), /* .memSize */ + UA_TYPES_SIGNATUREDATA, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 458, /* .binaryEncodingId */ + SignatureData_members /* .members */ +}, +/* ObjectTypeAttributes */ +{ + UA_TYPENAME("ObjectTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {361}}, /* .typeId */ + sizeof(UA_ObjectTypeAttributes), /* .memSize */ + UA_TYPES_OBJECTTYPEATTRIBUTES, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 363, /* .binaryEncodingId */ + ObjectTypeAttributes_members /* .members */ +}, +/* DeadbandType */ +{ + UA_TYPENAME("DeadbandType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {718}}, /* .typeId */ + sizeof(UA_DeadbandType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + DeadbandType_members /* .members */ +}, +/* SecurityTokenRequestType */ +{ + UA_TYPENAME("SecurityTokenRequestType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {315}}, /* .typeId */ + sizeof(UA_SecurityTokenRequestType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + SecurityTokenRequestType_members /* .members */ +}, +/* NodeAttributes */ +{ + UA_TYPENAME("NodeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {349}}, /* .typeId */ + sizeof(UA_NodeAttributes), /* .memSize */ + UA_TYPES_NODEATTRIBUTES, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 351, /* .binaryEncodingId */ + NodeAttributes_members /* .members */ +}, +/* DataChangeTrigger */ +{ + UA_TYPENAME("DataChangeTrigger") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {717}}, /* .typeId */ + sizeof(UA_DataChangeTrigger), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + DataChangeTrigger_members /* .members */ +}, +/* BuildInfo */ +{ + UA_TYPENAME("BuildInfo") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {338}}, /* .typeId */ + sizeof(UA_BuildInfo), /* .memSize */ + UA_TYPES_BUILDINFO, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 340, /* .binaryEncodingId */ + BuildInfo_members /* .members */ +}, +/* NodeClass */ +{ + UA_TYPENAME("NodeClass") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {257}}, /* .typeId */ + sizeof(UA_NodeClass), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + NodeClass_members /* .members */ +}, +/* SubscriptionDiagnosticsDataType */ +{ + UA_TYPENAME("SubscriptionDiagnosticsDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {874}}, /* .typeId */ + sizeof(UA_SubscriptionDiagnosticsDataType), /* .memSize */ + UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE, /* .typeIndex */ + 31, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 876, /* .binaryEncodingId */ + SubscriptionDiagnosticsDataType_members /* .members */ +}, +/* FilterOperand */ +{ + UA_TYPENAME("FilterOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {589}}, /* .typeId */ + sizeof(UA_FilterOperand), /* .memSize */ + UA_TYPES_FILTEROPERAND, /* .typeIndex */ + 0, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true, /* .overlayable */ + 591, /* .binaryEncodingId */ + FilterOperand_members /* .members */ +}, +/* MonitoredItemNotification */ +{ + UA_TYPENAME("MonitoredItemNotification") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {806}}, /* .typeId */ + sizeof(UA_MonitoredItemNotification), /* .memSize */ + UA_TYPES_MONITOREDITEMNOTIFICATION, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 808, /* .binaryEncodingId */ + MonitoredItemNotification_members /* .members */ +}, +/* DeleteNodesItem */ +{ + UA_TYPENAME("DeleteNodesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {382}}, /* .typeId */ + sizeof(UA_DeleteNodesItem), /* .memSize */ + UA_TYPES_DELETENODESITEM, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 384, /* .binaryEncodingId */ + DeleteNodesItem_members /* .members */ +}, +/* DeleteSubscriptionsRequest */ +{ + UA_TYPENAME("DeleteSubscriptionsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {845}}, /* .typeId */ + sizeof(UA_DeleteSubscriptionsRequest), /* .memSize */ + UA_TYPES_DELETESUBSCRIPTIONSREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 847, /* .binaryEncodingId */ + DeleteSubscriptionsRequest_members /* .members */ +}, +/* SubscriptionAcknowledgement */ +{ + UA_TYPENAME("SubscriptionAcknowledgement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {821}}, /* .typeId */ + sizeof(UA_SubscriptionAcknowledgement), /* .memSize */ + UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_SubscriptionAcknowledgement, sequenceNumber) == (offsetof(UA_SubscriptionAcknowledgement, subscriptionId) + sizeof(UA_UInt32)), /* .overlayable */ + 823, /* .binaryEncodingId */ + SubscriptionAcknowledgement_members /* .members */ +}, +/* ReadValueId */ +{ + UA_TYPENAME("ReadValueId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {626}}, /* .typeId */ + sizeof(UA_ReadValueId), /* .memSize */ + UA_TYPES_READVALUEID, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 628, /* .binaryEncodingId */ + ReadValueId_members /* .members */ +}, +/* DataTypeAttributes */ +{ + UA_TYPENAME("DataTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {370}}, /* .typeId */ + sizeof(UA_DataTypeAttributes), /* .memSize */ + UA_TYPES_DATATYPEATTRIBUTES, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 372, /* .binaryEncodingId */ + DataTypeAttributes_members /* .members */ +}, +/* ResponseHeader */ +{ + UA_TYPENAME("ResponseHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {392}}, /* .typeId */ + sizeof(UA_ResponseHeader), /* .memSize */ + UA_TYPES_RESPONSEHEADER, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 394, /* .binaryEncodingId */ + ResponseHeader_members /* .members */ +}, +/* DeleteMonitoredItemsRequest */ +{ + UA_TYPENAME("DeleteMonitoredItemsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {779}}, /* .typeId */ + sizeof(UA_DeleteMonitoredItemsRequest), /* .memSize */ + UA_TYPES_DELETEMONITOREDITEMSREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 781, /* .binaryEncodingId */ + DeleteMonitoredItemsRequest_members /* .members */ +}, +/* ViewDescription */ +{ + UA_TYPENAME("ViewDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {511}}, /* .typeId */ + sizeof(UA_ViewDescription), /* .memSize */ + UA_TYPES_VIEWDESCRIPTION, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 513, /* .binaryEncodingId */ + ViewDescription_members /* .members */ +}, +/* ServerOnNetwork */ +{ + UA_TYPENAME("ServerOnNetwork") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12189}}, /* .typeId */ + sizeof(UA_ServerOnNetwork), /* .memSize */ + UA_TYPES_SERVERONNETWORK, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 12207, /* .binaryEncodingId */ + ServerOnNetwork_members /* .members */ +}, +/* DeleteMonitoredItemsResponse */ +{ + UA_TYPENAME("DeleteMonitoredItemsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {782}}, /* .typeId */ + sizeof(UA_DeleteMonitoredItemsResponse), /* .memSize */ + UA_TYPES_DELETEMONITOREDITEMSRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 784, /* .binaryEncodingId */ + DeleteMonitoredItemsResponse_members /* .members */ +}, +/* FindServersOnNetworkResponse */ +{ + UA_TYPENAME("FindServersOnNetworkResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12191}}, /* .typeId */ + sizeof(UA_FindServersOnNetworkResponse), /* .memSize */ + UA_TYPES_FINDSERVERSONNETWORKRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 12209, /* .binaryEncodingId */ + FindServersOnNetworkResponse_members /* .members */ +}, +/* RelativePath */ +{ + UA_TYPENAME("RelativePath") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {540}}, /* .typeId */ + sizeof(UA_RelativePath), /* .memSize */ + UA_TYPES_RELATIVEPATH, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 542, /* .binaryEncodingId */ + RelativePath_members /* .members */ +}, +/* RegisterNodesRequest */ +{ + UA_TYPENAME("RegisterNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {558}}, /* .typeId */ + sizeof(UA_RegisterNodesRequest), /* .memSize */ + UA_TYPES_REGISTERNODESREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 560, /* .binaryEncodingId */ + RegisterNodesRequest_members /* .members */ +}, +/* AggregateConfiguration */ +{ + UA_TYPENAME("AggregateConfiguration") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {948}}, /* .typeId */ + sizeof(UA_AggregateConfiguration), /* .memSize */ + UA_TYPES_AGGREGATECONFIGURATION, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && true + && true + && offsetof(UA_AggregateConfiguration, treatUncertainAsBad) == (offsetof(UA_AggregateConfiguration, useServerCapabilitiesDefaults) + sizeof(UA_Boolean)) + && true + && offsetof(UA_AggregateConfiguration, percentDataBad) == (offsetof(UA_AggregateConfiguration, treatUncertainAsBad) + sizeof(UA_Boolean)) + && true + && offsetof(UA_AggregateConfiguration, percentDataGood) == (offsetof(UA_AggregateConfiguration, percentDataBad) + sizeof(UA_Byte)) + && true + && offsetof(UA_AggregateConfiguration, useSlopedExtrapolation) == (offsetof(UA_AggregateConfiguration, percentDataGood) + sizeof(UA_Byte)), /* .overlayable */ + 950, /* .binaryEncodingId */ + AggregateConfiguration_members /* .members */ +}, +/* DeleteNodesRequest */ +{ + UA_TYPENAME("DeleteNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {498}}, /* .typeId */ + sizeof(UA_DeleteNodesRequest), /* .memSize */ + UA_TYPES_DELETENODESREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 500, /* .binaryEncodingId */ + DeleteNodesRequest_members /* .members */ +}, +/* PublishResponse */ +{ + UA_TYPENAME("PublishResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {827}}, /* .typeId */ + sizeof(UA_PublishResponse), /* .memSize */ + UA_TYPES_PUBLISHRESPONSE, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 829, /* .binaryEncodingId */ + PublishResponse_members /* .members */ +}, +/* MonitoredItemModifyRequest */ +{ + UA_TYPENAME("MonitoredItemModifyRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {755}}, /* .typeId */ + sizeof(UA_MonitoredItemModifyRequest), /* .memSize */ + UA_TYPES_MONITOREDITEMMODIFYREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 757, /* .binaryEncodingId */ + MonitoredItemModifyRequest_members /* .members */ +}, +/* ServiceCounterDataType */ +{ + UA_TYPENAME("ServiceCounterDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {871}}, /* .typeId */ + sizeof(UA_ServiceCounterDataType), /* .memSize */ + UA_TYPES_SERVICECOUNTERDATATYPE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServiceCounterDataType, errorCount) == (offsetof(UA_ServiceCounterDataType, totalCount) + sizeof(UA_UInt32)), /* .overlayable */ + 873, /* .binaryEncodingId */ + ServiceCounterDataType_members /* .members */ +}, +/* ModelChangeStructureDataType */ +{ + UA_TYPENAME("ModelChangeStructureDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {877}}, /* .typeId */ + sizeof(UA_ModelChangeStructureDataType), /* .memSize */ + UA_TYPES_MODELCHANGESTRUCTUREDATATYPE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 879, /* .binaryEncodingId */ + ModelChangeStructureDataType_members /* .members */ +}, +/* UserNameIdentityToken */ +{ + UA_TYPENAME("UserNameIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {322}}, /* .typeId */ + sizeof(UA_UserNameIdentityToken), /* .memSize */ + UA_TYPES_USERNAMEIDENTITYTOKEN, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 324, /* .binaryEncodingId */ + UserNameIdentityToken_members /* .members */ +}, +/* IdType */ +{ + UA_TYPENAME("IdType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {256}}, /* .typeId */ + sizeof(UA_IdType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + IdType_members /* .members */ +}, +/* UserTokenType */ +{ + UA_TYPENAME("UserTokenType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {303}}, /* .typeId */ + sizeof(UA_UserTokenType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + UserTokenType_members /* .members */ +}, +/* SetTriggeringResponse */ +{ + UA_TYPENAME("SetTriggeringResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {776}}, /* .typeId */ + sizeof(UA_SetTriggeringResponse), /* .memSize */ + UA_TYPES_SETTRIGGERINGRESPONSE, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 778, /* .binaryEncodingId */ + SetTriggeringResponse_members /* .members */ +}, +/* TimeZoneDataType */ +{ + UA_TYPENAME("TimeZoneDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {8912}}, /* .typeId */ + sizeof(UA_TimeZoneDataType), /* .memSize */ + UA_TYPES_TIMEZONEDATATYPE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && true + && offsetof(UA_TimeZoneDataType, daylightSavingInOffset) == (offsetof(UA_TimeZoneDataType, offset) + sizeof(UA_Int16)), /* .overlayable */ + 8917, /* .binaryEncodingId */ + TimeZoneDataType_members /* .members */ +}, +/* ActivateSessionRequest */ +{ + UA_TYPENAME("ActivateSessionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {465}}, /* .typeId */ + sizeof(UA_ActivateSessionRequest), /* .memSize */ + UA_TYPES_ACTIVATESESSIONREQUEST, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 467, /* .binaryEncodingId */ + ActivateSessionRequest_members /* .members */ +}, +/* OpenSecureChannelResponse */ +{ + UA_TYPENAME("OpenSecureChannelResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {447}}, /* .typeId */ + sizeof(UA_OpenSecureChannelResponse), /* .memSize */ + UA_TYPES_OPENSECURECHANNELRESPONSE, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 449, /* .binaryEncodingId */ + OpenSecureChannelResponse_members /* .members */ +}, +/* ApplicationType */ +{ + UA_TYPENAME("ApplicationType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {307}}, /* .typeId */ + sizeof(UA_ApplicationType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + ApplicationType_members /* .members */ +}, +/* ServerState */ +{ + UA_TYPENAME("ServerState") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {852}}, /* .typeId */ + sizeof(UA_ServerState), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + ServerState_members /* .members */ +}, +/* QueryNextResponse */ +{ + UA_TYPENAME("QueryNextResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {622}}, /* .typeId */ + sizeof(UA_QueryNextResponse), /* .memSize */ + UA_TYPES_QUERYNEXTRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 624, /* .binaryEncodingId */ + QueryNextResponse_members /* .members */ +}, +/* DiscoveryConfiguration */ +{ + UA_TYPENAME("DiscoveryConfiguration") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12890}}, /* .typeId */ + sizeof(UA_DiscoveryConfiguration), /* .memSize */ + UA_TYPES_DISCOVERYCONFIGURATION, /* .typeIndex */ + 0, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true, /* .overlayable */ + 12900, /* .binaryEncodingId */ + DiscoveryConfiguration_members /* .members */ +}, +/* ActivateSessionResponse */ +{ + UA_TYPENAME("ActivateSessionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {468}}, /* .typeId */ + sizeof(UA_ActivateSessionResponse), /* .memSize */ + UA_TYPES_ACTIVATESESSIONRESPONSE, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 470, /* .binaryEncodingId */ + ActivateSessionResponse_members /* .members */ +}, +/* EndpointUrlListDataType */ +{ + UA_TYPENAME("EndpointUrlListDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {11943}}, /* .typeId */ + sizeof(UA_EndpointUrlListDataType), /* .memSize */ + UA_TYPES_ENDPOINTURLLISTDATATYPE, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 11957, /* .binaryEncodingId */ + EndpointUrlListDataType_members /* .members */ +}, +/* FilterOperator */ +{ + UA_TYPENAME("FilterOperator") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {576}}, /* .typeId */ + sizeof(UA_FilterOperator), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + FilterOperator_members /* .members */ +}, +/* QueryNextRequest */ +{ + UA_TYPENAME("QueryNextRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {619}}, /* .typeId */ + sizeof(UA_QueryNextRequest), /* .memSize */ + UA_TYPES_QUERYNEXTREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 621, /* .binaryEncodingId */ + QueryNextRequest_members /* .members */ +}, +/* WriteResponse */ +{ + UA_TYPENAME("WriteResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {674}}, /* .typeId */ + sizeof(UA_WriteResponse), /* .memSize */ + UA_TYPES_WRITERESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 676, /* .binaryEncodingId */ + WriteResponse_members /* .members */ +}, +/* BrowseNextRequest */ +{ + UA_TYPENAME("BrowseNextRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {531}}, /* .typeId */ + sizeof(UA_BrowseNextRequest), /* .memSize */ + UA_TYPES_BROWSENEXTREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 533, /* .binaryEncodingId */ + BrowseNextRequest_members /* .members */ +}, +/* CreateSubscriptionRequest */ +{ + UA_TYPENAME("CreateSubscriptionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {785}}, /* .typeId */ + sizeof(UA_CreateSubscriptionRequest), /* .memSize */ + UA_TYPES_CREATESUBSCRIPTIONREQUEST, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 787, /* .binaryEncodingId */ + CreateSubscriptionRequest_members /* .members */ +}, +/* VariableTypeAttributes */ +{ + UA_TYPENAME("VariableTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {364}}, /* .typeId */ + sizeof(UA_VariableTypeAttributes), /* .memSize */ + UA_TYPES_VARIABLETYPEATTRIBUTES, /* .typeIndex */ + 10, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 366, /* .binaryEncodingId */ + VariableTypeAttributes_members /* .members */ +}, +/* BrowsePathResult */ +{ + UA_TYPENAME("BrowsePathResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {549}}, /* .typeId */ + sizeof(UA_BrowsePathResult), /* .memSize */ + UA_TYPES_BROWSEPATHRESULT, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 551, /* .binaryEncodingId */ + BrowsePathResult_members /* .members */ +}, +/* ModifySubscriptionResponse */ +{ + UA_TYPENAME("ModifySubscriptionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {794}}, /* .typeId */ + sizeof(UA_ModifySubscriptionResponse), /* .memSize */ + UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 796, /* .binaryEncodingId */ + ModifySubscriptionResponse_members /* .members */ +}, +/* RedundantServerDataType */ +{ + UA_TYPENAME("RedundantServerDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {853}}, /* .typeId */ + sizeof(UA_RedundantServerDataType), /* .memSize */ + UA_TYPES_REDUNDANTSERVERDATATYPE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 855, /* .binaryEncodingId */ + RedundantServerDataType_members /* .members */ +}, +/* RegisterNodesResponse */ +{ + UA_TYPENAME("RegisterNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {561}}, /* .typeId */ + sizeof(UA_RegisterNodesResponse), /* .memSize */ + UA_TYPES_REGISTERNODESRESPONSE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 563, /* .binaryEncodingId */ + RegisterNodesResponse_members /* .members */ +}, +/* CloseSessionRequest */ +{ + UA_TYPENAME("CloseSessionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {471}}, /* .typeId */ + sizeof(UA_CloseSessionRequest), /* .memSize */ + UA_TYPES_CLOSESESSIONREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 473, /* .binaryEncodingId */ + CloseSessionRequest_members /* .members */ +}, +/* ModifyMonitoredItemsResponse */ +{ + UA_TYPENAME("ModifyMonitoredItemsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {764}}, /* .typeId */ + sizeof(UA_ModifyMonitoredItemsResponse), /* .memSize */ + UA_TYPES_MODIFYMONITOREDITEMSRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 766, /* .binaryEncodingId */ + ModifyMonitoredItemsResponse_members /* .members */ +}, +/* ModifySubscriptionRequest */ +{ + UA_TYPENAME("ModifySubscriptionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {791}}, /* .typeId */ + sizeof(UA_ModifySubscriptionRequest), /* .memSize */ + UA_TYPES_MODIFYSUBSCRIPTIONREQUEST, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 793, /* .binaryEncodingId */ + ModifySubscriptionRequest_members /* .members */ +}, +/* ServerDiagnosticsSummaryDataType */ +{ + UA_TYPENAME("ServerDiagnosticsSummaryDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {859}}, /* .typeId */ + sizeof(UA_ServerDiagnosticsSummaryDataType), /* .memSize */ + UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE, /* .typeIndex */ + 12, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, serverViewCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedRequestsCount) == (offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) + sizeof(UA_UInt32)), /* .overlayable */ + 861, /* .binaryEncodingId */ + ServerDiagnosticsSummaryDataType_members /* .members */ +}, +/* UserTokenPolicy */ +{ + UA_TYPENAME("UserTokenPolicy") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {304}}, /* .typeId */ + sizeof(UA_UserTokenPolicy), /* .memSize */ + UA_TYPES_USERTOKENPOLICY, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 306, /* .binaryEncodingId */ + UserTokenPolicy_members /* .members */ +}, +/* ReferenceTypeAttributes */ +{ + UA_TYPENAME("ReferenceTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {367}}, /* .typeId */ + sizeof(UA_ReferenceTypeAttributes), /* .memSize */ + UA_TYPES_REFERENCETYPEATTRIBUTES, /* .typeIndex */ + 8, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 369, /* .binaryEncodingId */ + ReferenceTypeAttributes_members /* .members */ +}, +/* BrowsePath */ +{ + UA_TYPENAME("BrowsePath") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {543}}, /* .typeId */ + sizeof(UA_BrowsePath), /* .memSize */ + UA_TYPES_BROWSEPATH, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 545, /* .binaryEncodingId */ + BrowsePath_members /* .members */ +}, +/* SetMonitoringModeRequest */ +{ + UA_TYPENAME("SetMonitoringModeRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {767}}, /* .typeId */ + sizeof(UA_SetMonitoringModeRequest), /* .memSize */ + UA_TYPES_SETMONITORINGMODEREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 769, /* .binaryEncodingId */ + SetMonitoringModeRequest_members /* .members */ +}, +/* UnregisterNodesResponse */ +{ + UA_TYPENAME("UnregisterNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {567}}, /* .typeId */ + sizeof(UA_UnregisterNodesResponse), /* .memSize */ + UA_TYPES_UNREGISTERNODESRESPONSE, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 569, /* .binaryEncodingId */ + UnregisterNodesResponse_members /* .members */ +}, +/* WriteRequest */ +{ + UA_TYPENAME("WriteRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {671}}, /* .typeId */ + sizeof(UA_WriteRequest), /* .memSize */ + UA_TYPES_WRITEREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 673, /* .binaryEncodingId */ + WriteRequest_members /* .members */ +}, +/* ObjectAttributes */ +{ + UA_TYPENAME("ObjectAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {352}}, /* .typeId */ + sizeof(UA_ObjectAttributes), /* .memSize */ + UA_TYPES_OBJECTATTRIBUTES, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 354, /* .binaryEncodingId */ + ObjectAttributes_members /* .members */ +}, +/* BrowseResultMask */ +{ + UA_TYPENAME("BrowseResultMask") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {517}}, /* .typeId */ + sizeof(UA_BrowseResultMask), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + BrowseResultMask_members /* .members */ +}, +/* BrowseDescription */ +{ + UA_TYPENAME("BrowseDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {514}}, /* .typeId */ + sizeof(UA_BrowseDescription), /* .memSize */ + UA_TYPES_BROWSEDESCRIPTION, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 516, /* .binaryEncodingId */ + BrowseDescription_members /* .members */ +}, +/* SetTriggeringRequest */ +{ + UA_TYPENAME("SetTriggeringRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {773}}, /* .typeId */ + sizeof(UA_SetTriggeringRequest), /* .memSize */ + UA_TYPES_SETTRIGGERINGREQUEST, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 775, /* .binaryEncodingId */ + SetTriggeringRequest_members /* .members */ +}, +/* SessionSecurityDiagnosticsDataType */ +{ + UA_TYPENAME("SessionSecurityDiagnosticsDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {868}}, /* .typeId */ + sizeof(UA_SessionSecurityDiagnosticsDataType), /* .memSize */ + UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE, /* .typeIndex */ + 9, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 870, /* .binaryEncodingId */ + SessionSecurityDiagnosticsDataType_members /* .members */ +}, +/* RepublishRequest */ +{ + UA_TYPENAME("RepublishRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {830}}, /* .typeId */ + sizeof(UA_RepublishRequest), /* .memSize */ + UA_TYPES_REPUBLISHREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 832, /* .binaryEncodingId */ + RepublishRequest_members /* .members */ +}, +/* GetEndpointsRequest */ +{ + UA_TYPENAME("GetEndpointsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {426}}, /* .typeId */ + sizeof(UA_GetEndpointsRequest), /* .memSize */ + UA_TYPES_GETENDPOINTSREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 428, /* .binaryEncodingId */ + GetEndpointsRequest_members /* .members */ +}, +/* PublishRequest */ +{ + UA_TYPENAME("PublishRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {824}}, /* .typeId */ + sizeof(UA_PublishRequest), /* .memSize */ + UA_TYPES_PUBLISHREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 826, /* .binaryEncodingId */ + PublishRequest_members /* .members */ +}, +/* DeleteSubscriptionsResponse */ +{ + UA_TYPENAME("DeleteSubscriptionsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {848}}, /* .typeId */ + sizeof(UA_DeleteSubscriptionsResponse), /* .memSize */ + UA_TYPES_DELETESUBSCRIPTIONSRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 850, /* .binaryEncodingId */ + DeleteSubscriptionsResponse_members /* .members */ +}, +/* AddNodesResponse */ +{ + UA_TYPENAME("AddNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {489}}, /* .typeId */ + sizeof(UA_AddNodesResponse), /* .memSize */ + UA_TYPES_ADDNODESRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 491, /* .binaryEncodingId */ + AddNodesResponse_members /* .members */ +}, +/* DataChangeNotification */ +{ + UA_TYPENAME("DataChangeNotification") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {809}}, /* .typeId */ + sizeof(UA_DataChangeNotification), /* .memSize */ + UA_TYPES_DATACHANGENOTIFICATION, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 811, /* .binaryEncodingId */ + DataChangeNotification_members /* .members */ +}, +/* CloseSecureChannelResponse */ +{ + UA_TYPENAME("CloseSecureChannelResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {453}}, /* .typeId */ + sizeof(UA_CloseSecureChannelResponse), /* .memSize */ + UA_TYPES_CLOSESECURECHANNELRESPONSE, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 455, /* .binaryEncodingId */ + CloseSecureChannelResponse_members /* .members */ +}, +/* ModifyMonitoredItemsRequest */ +{ + UA_TYPENAME("ModifyMonitoredItemsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {761}}, /* .typeId */ + sizeof(UA_ModifyMonitoredItemsRequest), /* .memSize */ + UA_TYPES_MODIFYMONITOREDITEMSREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 763, /* .binaryEncodingId */ + ModifyMonitoredItemsRequest_members /* .members */ +}, +/* SetMonitoringModeResponse */ +{ + UA_TYPENAME("SetMonitoringModeResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {770}}, /* .typeId */ + sizeof(UA_SetMonitoringModeResponse), /* .memSize */ + UA_TYPES_SETMONITORINGMODERESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 772, /* .binaryEncodingId */ + SetMonitoringModeResponse_members /* .members */ +}, +/* FindServersRequest */ +{ + UA_TYPENAME("FindServersRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {420}}, /* .typeId */ + sizeof(UA_FindServersRequest), /* .memSize */ + UA_TYPES_FINDSERVERSREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 422, /* .binaryEncodingId */ + FindServersRequest_members /* .members */ +}, +/* ReferenceDescription */ +{ + UA_TYPENAME("ReferenceDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {518}}, /* .typeId */ + sizeof(UA_ReferenceDescription), /* .memSize */ + UA_TYPES_REFERENCEDESCRIPTION, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 520, /* .binaryEncodingId */ + ReferenceDescription_members /* .members */ +}, +/* SetPublishingModeResponse */ +{ + UA_TYPENAME("SetPublishingModeResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {800}}, /* .typeId */ + sizeof(UA_SetPublishingModeResponse), /* .memSize */ + UA_TYPES_SETPUBLISHINGMODERESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 802, /* .binaryEncodingId */ + SetPublishingModeResponse_members /* .members */ +}, +/* ContentFilterResult */ +{ + UA_TYPENAME("ContentFilterResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {607}}, /* .typeId */ + sizeof(UA_ContentFilterResult), /* .memSize */ + UA_TYPES_CONTENTFILTERRESULT, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 609, /* .binaryEncodingId */ + ContentFilterResult_members /* .members */ +}, +/* RegisterServerResponse */ +{ + UA_TYPENAME("RegisterServerResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {438}}, /* .typeId */ + sizeof(UA_RegisterServerResponse), /* .memSize */ + UA_TYPES_REGISTERSERVERRESPONSE, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 440, /* .binaryEncodingId */ + RegisterServerResponse_members /* .members */ +}, +/* AddReferencesItem */ +{ + UA_TYPENAME("AddReferencesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {379}}, /* .typeId */ + sizeof(UA_AddReferencesItem), /* .memSize */ + UA_TYPES_ADDREFERENCESITEM, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 381, /* .binaryEncodingId */ + AddReferencesItem_members /* .members */ +}, +/* QueryDataDescription */ +{ + UA_TYPENAME("QueryDataDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {570}}, /* .typeId */ + sizeof(UA_QueryDataDescription), /* .memSize */ + UA_TYPES_QUERYDATADESCRIPTION, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 572, /* .binaryEncodingId */ + QueryDataDescription_members /* .members */ +}, +/* CreateSubscriptionResponse */ +{ + UA_TYPENAME("CreateSubscriptionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {788}}, /* .typeId */ + sizeof(UA_CreateSubscriptionResponse), /* .memSize */ + UA_TYPES_CREATESUBSCRIPTIONRESPONSE, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 790, /* .binaryEncodingId */ + CreateSubscriptionResponse_members /* .members */ +}, +/* NetworkGroupDataType */ +{ + UA_TYPENAME("NetworkGroupDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {11944}}, /* .typeId */ + sizeof(UA_NetworkGroupDataType), /* .memSize */ + UA_TYPES_NETWORKGROUPDATATYPE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 11958, /* .binaryEncodingId */ + NetworkGroupDataType_members /* .members */ +}, +/* DeleteReferencesResponse */ +{ + UA_TYPENAME("DeleteReferencesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {507}}, /* .typeId */ + sizeof(UA_DeleteReferencesResponse), /* .memSize */ + UA_TYPES_DELETEREFERENCESRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 509, /* .binaryEncodingId */ + DeleteReferencesResponse_members /* .members */ +}, +/* CreateMonitoredItemsResponse */ +{ + UA_TYPENAME("CreateMonitoredItemsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {752}}, /* .typeId */ + sizeof(UA_CreateMonitoredItemsResponse), /* .memSize */ + UA_TYPES_CREATEMONITOREDITEMSRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 754, /* .binaryEncodingId */ + CreateMonitoredItemsResponse_members /* .members */ +}, +/* CallResponse */ +{ + UA_TYPENAME("CallResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {713}}, /* .typeId */ + sizeof(UA_CallResponse), /* .memSize */ + UA_TYPES_CALLRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 715, /* .binaryEncodingId */ + CallResponse_members /* .members */ +}, +/* DeleteNodesResponse */ +{ + UA_TYPENAME("DeleteNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {501}}, /* .typeId */ + sizeof(UA_DeleteNodesResponse), /* .memSize */ + UA_TYPES_DELETENODESRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 503, /* .binaryEncodingId */ + DeleteNodesResponse_members /* .members */ +}, +/* RepublishResponse */ +{ + UA_TYPENAME("RepublishResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {833}}, /* .typeId */ + sizeof(UA_RepublishResponse), /* .memSize */ + UA_TYPES_REPUBLISHRESPONSE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 835, /* .binaryEncodingId */ + RepublishResponse_members /* .members */ +}, +/* MonitoredItemCreateRequest */ +{ + UA_TYPENAME("MonitoredItemCreateRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {743}}, /* .typeId */ + sizeof(UA_MonitoredItemCreateRequest), /* .memSize */ + UA_TYPES_MONITOREDITEMCREATEREQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 745, /* .binaryEncodingId */ + MonitoredItemCreateRequest_members /* .members */ +}, +/* DeleteReferencesRequest */ +{ + UA_TYPENAME("DeleteReferencesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {504}}, /* .typeId */ + sizeof(UA_DeleteReferencesRequest), /* .memSize */ + UA_TYPES_DELETEREFERENCESREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 506, /* .binaryEncodingId */ + DeleteReferencesRequest_members /* .members */ +}, +/* ReadResponse */ +{ + UA_TYPENAME("ReadResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {632}}, /* .typeId */ + sizeof(UA_ReadResponse), /* .memSize */ + UA_TYPES_READRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 634, /* .binaryEncodingId */ + ReadResponse_members /* .members */ +}, +/* AddReferencesRequest */ +{ + UA_TYPENAME("AddReferencesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {492}}, /* .typeId */ + sizeof(UA_AddReferencesRequest), /* .memSize */ + UA_TYPES_ADDREFERENCESREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 494, /* .binaryEncodingId */ + AddReferencesRequest_members /* .members */ +}, +/* ReadRequest */ +{ + UA_TYPENAME("ReadRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {629}}, /* .typeId */ + sizeof(UA_ReadRequest), /* .memSize */ + UA_TYPES_READREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 631, /* .binaryEncodingId */ + ReadRequest_members /* .members */ +}, +/* OpenSecureChannelRequest */ +{ + UA_TYPENAME("OpenSecureChannelRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {444}}, /* .typeId */ + sizeof(UA_OpenSecureChannelRequest), /* .memSize */ + UA_TYPES_OPENSECURECHANNELREQUEST, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 446, /* .binaryEncodingId */ + OpenSecureChannelRequest_members /* .members */ +}, +/* RegisterServer2Response */ +{ + UA_TYPENAME("RegisterServer2Response") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12194}}, /* .typeId */ + sizeof(UA_RegisterServer2Response), /* .memSize */ + UA_TYPES_REGISTERSERVER2RESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 12212, /* .binaryEncodingId */ + RegisterServer2Response_members /* .members */ +}, +/* AddNodesItem */ +{ + UA_TYPENAME("AddNodesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {376}}, /* .typeId */ + sizeof(UA_AddNodesItem), /* .memSize */ + UA_TYPES_ADDNODESITEM, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 378, /* .binaryEncodingId */ + AddNodesItem_members /* .members */ +}, +/* NodeTypeDescription */ +{ + UA_TYPENAME("NodeTypeDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {573}}, /* .typeId */ + sizeof(UA_NodeTypeDescription), /* .memSize */ + UA_TYPES_NODETYPEDESCRIPTION, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 575, /* .binaryEncodingId */ + NodeTypeDescription_members /* .members */ +}, +/* ServerStatusDataType */ +{ + UA_TYPENAME("ServerStatusDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {862}}, /* .typeId */ + sizeof(UA_ServerStatusDataType), /* .memSize */ + UA_TYPES_SERVERSTATUSDATATYPE, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 864, /* .binaryEncodingId */ + ServerStatusDataType_members /* .members */ +}, +/* AttributeOperand */ +{ + UA_TYPENAME("AttributeOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {598}}, /* .typeId */ + sizeof(UA_AttributeOperand), /* .memSize */ + UA_TYPES_ATTRIBUTEOPERAND, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 600, /* .binaryEncodingId */ + AttributeOperand_members /* .members */ +}, +/* AddReferencesResponse */ +{ + UA_TYPENAME("AddReferencesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {495}}, /* .typeId */ + sizeof(UA_AddReferencesResponse), /* .memSize */ + UA_TYPES_ADDREFERENCESRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 497, /* .binaryEncodingId */ + AddReferencesResponse_members /* .members */ +}, +/* EventFilterResult */ +{ + UA_TYPENAME("EventFilterResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {734}}, /* .typeId */ + sizeof(UA_EventFilterResult), /* .memSize */ + UA_TYPES_EVENTFILTERRESULT, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 736, /* .binaryEncodingId */ + EventFilterResult_members /* .members */ +}, +/* TranslateBrowsePathsToNodeIdsResponse */ +{ + UA_TYPENAME("TranslateBrowsePathsToNodeIdsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {555}}, /* .typeId */ + sizeof(UA_TranslateBrowsePathsToNodeIdsResponse), /* .memSize */ + UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 557, /* .binaryEncodingId */ + TranslateBrowsePathsToNodeIdsResponse_members /* .members */ +}, +/* DataChangeFilter */ +{ + UA_TYPENAME("DataChangeFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {722}}, /* .typeId */ + sizeof(UA_DataChangeFilter), /* .memSize */ + UA_TYPES_DATACHANGEFILTER, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_DataChangeFilter, deadbandType) == (offsetof(UA_DataChangeFilter, trigger) + sizeof(UA_DataChangeTrigger)) + && UA_BINARY_OVERLAYABLE_FLOAT + && offsetof(UA_DataChangeFilter, deadbandValue) == (offsetof(UA_DataChangeFilter, deadbandType) + sizeof(UA_UInt32)), /* .overlayable */ + 724, /* .binaryEncodingId */ + DataChangeFilter_members /* .members */ +}, +/* ContentFilterElement */ +{ + UA_TYPENAME("ContentFilterElement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {583}}, /* .typeId */ + sizeof(UA_ContentFilterElement), /* .memSize */ + UA_TYPES_CONTENTFILTERELEMENT, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 585, /* .binaryEncodingId */ + ContentFilterElement_members /* .members */ +}, +/* TranslateBrowsePathsToNodeIdsRequest */ +{ + UA_TYPENAME("TranslateBrowsePathsToNodeIdsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {552}}, /* .typeId */ + sizeof(UA_TranslateBrowsePathsToNodeIdsRequest), /* .memSize */ + UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 554, /* .binaryEncodingId */ + TranslateBrowsePathsToNodeIdsRequest_members /* .members */ +}, +/* CloseSessionResponse */ +{ + UA_TYPENAME("CloseSessionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {474}}, /* .typeId */ + sizeof(UA_CloseSessionResponse), /* .memSize */ + UA_TYPES_CLOSESESSIONRESPONSE, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 476, /* .binaryEncodingId */ + CloseSessionResponse_members /* .members */ +}, +/* ApplicationDescription */ +{ + UA_TYPENAME("ApplicationDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {308}}, /* .typeId */ + sizeof(UA_ApplicationDescription), /* .memSize */ + UA_TYPES_APPLICATIONDESCRIPTION, /* .typeIndex */ + 7, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 310, /* .binaryEncodingId */ + ApplicationDescription_members /* .members */ +}, +/* SessionDiagnosticsDataType */ +{ + UA_TYPENAME("SessionDiagnosticsDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {865}}, /* .typeId */ + sizeof(UA_SessionDiagnosticsDataType), /* .memSize */ + UA_TYPES_SESSIONDIAGNOSTICSDATATYPE, /* .typeIndex */ + 43, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 867, /* .binaryEncodingId */ + SessionDiagnosticsDataType_members /* .members */ +}, +/* ServiceFault */ +{ + UA_TYPENAME("ServiceFault") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {395}}, /* .typeId */ + sizeof(UA_ServiceFault), /* .memSize */ + UA_TYPES_SERVICEFAULT, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 397, /* .binaryEncodingId */ + ServiceFault_members /* .members */ +}, +/* RegisteredServer */ +{ + UA_TYPENAME("RegisteredServer") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {432}}, /* .typeId */ + sizeof(UA_RegisteredServer), /* .memSize */ + UA_TYPES_REGISTEREDSERVER, /* .typeIndex */ + 8, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 434, /* .binaryEncodingId */ + RegisteredServer_members /* .members */ +}, +/* AggregateFilter */ +{ + UA_TYPENAME("AggregateFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {728}}, /* .typeId */ + sizeof(UA_AggregateFilter), /* .memSize */ + UA_TYPES_AGGREGATEFILTER, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 730, /* .binaryEncodingId */ + AggregateFilter_members /* .members */ +}, +/* RegisterServerRequest */ +{ + UA_TYPENAME("RegisterServerRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {435}}, /* .typeId */ + sizeof(UA_RegisterServerRequest), /* .memSize */ + UA_TYPES_REGISTERSERVERREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 437, /* .binaryEncodingId */ + RegisterServerRequest_members /* .members */ +}, +/* EndpointDescription */ +{ + UA_TYPENAME("EndpointDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {312}}, /* .typeId */ + sizeof(UA_EndpointDescription), /* .memSize */ + UA_TYPES_ENDPOINTDESCRIPTION, /* .typeIndex */ + 8, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 314, /* .binaryEncodingId */ + EndpointDescription_members /* .members */ +}, +/* CreateMonitoredItemsRequest */ +{ + UA_TYPENAME("CreateMonitoredItemsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {749}}, /* .typeId */ + sizeof(UA_CreateMonitoredItemsRequest), /* .memSize */ + UA_TYPES_CREATEMONITOREDITEMSREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 751, /* .binaryEncodingId */ + CreateMonitoredItemsRequest_members /* .members */ +}, +/* ContentFilter */ +{ + UA_TYPENAME("ContentFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {586}}, /* .typeId */ + sizeof(UA_ContentFilter), /* .memSize */ + UA_TYPES_CONTENTFILTER, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 588, /* .binaryEncodingId */ + ContentFilter_members /* .members */ +}, +/* QueryFirstResponse */ +{ + UA_TYPENAME("QueryFirstResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {616}}, /* .typeId */ + sizeof(UA_QueryFirstResponse), /* .memSize */ + UA_TYPES_QUERYFIRSTRESPONSE, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 618, /* .binaryEncodingId */ + QueryFirstResponse_members /* .members */ +}, +/* AddNodesRequest */ +{ + UA_TYPENAME("AddNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {486}}, /* .typeId */ + sizeof(UA_AddNodesRequest), /* .memSize */ + UA_TYPES_ADDNODESREQUEST, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 488, /* .binaryEncodingId */ + AddNodesRequest_members /* .members */ +}, +/* BrowseRequest */ +{ + UA_TYPENAME("BrowseRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {525}}, /* .typeId */ + sizeof(UA_BrowseRequest), /* .memSize */ + UA_TYPES_BROWSEREQUEST, /* .typeIndex */ + 4, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 527, /* .binaryEncodingId */ + BrowseRequest_members /* .members */ +}, +/* BrowseResult */ +{ + UA_TYPENAME("BrowseResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {522}}, /* .typeId */ + sizeof(UA_BrowseResult), /* .memSize */ + UA_TYPES_BROWSERESULT, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 524, /* .binaryEncodingId */ + BrowseResult_members /* .members */ +}, +/* RegisterServer2Request */ +{ + UA_TYPENAME("RegisterServer2Request") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12193}}, /* .typeId */ + sizeof(UA_RegisterServer2Request), /* .memSize */ + UA_TYPES_REGISTERSERVER2REQUEST, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 12211, /* .binaryEncodingId */ + RegisterServer2Request_members /* .members */ +}, +/* CreateSessionRequest */ +{ + UA_TYPENAME("CreateSessionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {459}}, /* .typeId */ + sizeof(UA_CreateSessionRequest), /* .memSize */ + UA_TYPES_CREATESESSIONREQUEST, /* .typeIndex */ + 9, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 461, /* .binaryEncodingId */ + CreateSessionRequest_members /* .members */ +}, +/* EventFilter */ +{ + UA_TYPENAME("EventFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {725}}, /* .typeId */ + sizeof(UA_EventFilter), /* .memSize */ + UA_TYPES_EVENTFILTER, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 727, /* .binaryEncodingId */ + EventFilter_members /* .members */ +}, +/* GetEndpointsResponse */ +{ + UA_TYPENAME("GetEndpointsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {429}}, /* .typeId */ + sizeof(UA_GetEndpointsResponse), /* .memSize */ + UA_TYPES_GETENDPOINTSRESPONSE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 431, /* .binaryEncodingId */ + GetEndpointsResponse_members /* .members */ +}, +/* FindServersResponse */ +{ + UA_TYPENAME("FindServersResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {423}}, /* .typeId */ + sizeof(UA_FindServersResponse), /* .memSize */ + UA_TYPES_FINDSERVERSRESPONSE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 425, /* .binaryEncodingId */ + FindServersResponse_members /* .members */ +}, +/* BrowseNextResponse */ +{ + UA_TYPENAME("BrowseNextResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {534}}, /* .typeId */ + sizeof(UA_BrowseNextResponse), /* .memSize */ + UA_TYPES_BROWSENEXTRESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 536, /* .binaryEncodingId */ + BrowseNextResponse_members /* .members */ +}, +/* BrowseResponse */ +{ + UA_TYPENAME("BrowseResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {528}}, /* .typeId */ + sizeof(UA_BrowseResponse), /* .memSize */ + UA_TYPES_BROWSERESPONSE, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 530, /* .binaryEncodingId */ + BrowseResponse_members /* .members */ +}, +/* CreateSessionResponse */ +{ + UA_TYPENAME("CreateSessionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {462}}, /* .typeId */ + sizeof(UA_CreateSessionResponse), /* .memSize */ + UA_TYPES_CREATESESSIONRESPONSE, /* .typeIndex */ + 10, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 464, /* .binaryEncodingId */ + CreateSessionResponse_members /* .members */ +}, +/* QueryFirstRequest */ +{ + UA_TYPENAME("QueryFirstRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {613}}, /* .typeId */ + sizeof(UA_QueryFirstRequest), /* .memSize */ + UA_TYPES_QUERYFIRSTREQUEST, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 615, /* .binaryEncodingId */ + QueryFirstRequest_members /* .members */ +}, +}; + + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_transport_generated.c" ***********************************/ + +/* Generated from Opc.Ua.Types.bsd, Custom.Opc.Ua.Transport.bsd with script /home/jvoe/open62541/tools/generate_datatypes.py + * on host rigel by user jvoe at 2019-01-04 01:18:40 */ + + +/* SecureConversationMessageAbortBody */ +static UA_DataTypeMember SecureConversationMessageAbortBody_members[2] = { +{ + UA_TYPENAME("error") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("reason") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_SecureConversationMessageAbortBody, reason) - offsetof(UA_SecureConversationMessageAbortBody, error) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SecureConversationMessageFooter */ +static UA_DataTypeMember SecureConversationMessageFooter_members[2] = { +{ + UA_TYPENAME("padding") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + true /* .isArray */ +}, +{ + UA_TYPENAME("signature") /* .memberName */ + UA_TYPES_BYTE, /* .memberTypeIndex */ + offsetof(UA_SecureConversationMessageFooter, signature) - offsetof(UA_SecureConversationMessageFooter, padding) - sizeof(void*), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* TcpHelloMessage */ +static UA_DataTypeMember TcpHelloMessage_members[6] = { +{ + UA_TYPENAME("protocolVersion") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("receiveBufferSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpHelloMessage, receiveBufferSize) - offsetof(UA_TcpHelloMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sendBufferSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpHelloMessage, sendBufferSize) - offsetof(UA_TcpHelloMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxMessageSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpHelloMessage, maxMessageSize) - offsetof(UA_TcpHelloMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxChunkCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpHelloMessage, maxChunkCount) - offsetof(UA_TcpHelloMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("endpointUrl") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_TcpHelloMessage, endpointUrl) - offsetof(UA_TcpHelloMessage, maxChunkCount) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* TcpErrorMessage */ +static UA_DataTypeMember TcpErrorMessage_members[2] = { +{ + UA_TYPENAME("error") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("reason") /* .memberName */ + UA_TYPES_STRING, /* .memberTypeIndex */ + offsetof(UA_TcpErrorMessage, reason) - offsetof(UA_TcpErrorMessage, error) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* MessageType */ +static UA_DataTypeMember MessageType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* AsymmetricAlgorithmSecurityHeader */ +static UA_DataTypeMember AsymmetricAlgorithmSecurityHeader_members[3] = { +{ + UA_TYPENAME("securityPolicyUri") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("senderCertificate") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, securityPolicyUri) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("receiverCertificateThumbprint") /* .memberName */ + UA_TYPES_BYTESTRING, /* .memberTypeIndex */ + offsetof(UA_AsymmetricAlgorithmSecurityHeader, receiverCertificateThumbprint) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - sizeof(UA_ByteString), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* TcpAcknowledgeMessage */ +static UA_DataTypeMember TcpAcknowledgeMessage_members[5] = { +{ + UA_TYPENAME("protocolVersion") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("receiveBufferSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - offsetof(UA_TcpAcknowledgeMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("sendBufferSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxMessageSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("maxChunkCount") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpAcknowledgeMessage, maxChunkCount) - offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SequenceHeader */ +static UA_DataTypeMember SequenceHeader_members[2] = { +{ + UA_TYPENAME("sequenceNumber") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("requestId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SequenceHeader, requestId) - offsetof(UA_SequenceHeader, sequenceNumber) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* TcpMessageHeader */ +static UA_DataTypeMember TcpMessageHeader_members[2] = { +{ + UA_TYPENAME("messageTypeAndChunkType") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("messageSize") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_TcpMessageHeader, messageSize) - offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) - sizeof(UA_UInt32), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* ChunkType */ +static UA_DataTypeMember ChunkType_members[1] = { +{ + UA_TYPENAME("") /* .memberName */ + UA_TYPES_INT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SymmetricAlgorithmSecurityHeader */ +static UA_DataTypeMember SymmetricAlgorithmSecurityHeader_members[1] = { +{ + UA_TYPENAME("tokenId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + 0, /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; + +/* SecureConversationMessageHeader */ +static UA_DataTypeMember SecureConversationMessageHeader_members[2] = { +{ + UA_TYPENAME("messageHeader") /* .memberName */ + UA_TRANSPORT_TCPMESSAGEHEADER, /* .memberTypeIndex */ + 0, /* .padding */ + false, /* .namespaceZero */ + false /* .isArray */ +}, +{ + UA_TYPENAME("secureChannelId") /* .memberName */ + UA_TYPES_UINT32, /* .memberTypeIndex */ + offsetof(UA_SecureConversationMessageHeader, secureChannelId) - offsetof(UA_SecureConversationMessageHeader, messageHeader) - sizeof(UA_TcpMessageHeader), /* .padding */ + true, /* .namespaceZero */ + false /* .isArray */ +}}; +const UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT] = { +/* SecureConversationMessageAbortBody */ +{ + UA_TYPENAME("SecureConversationMessageAbortBody") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_SecureConversationMessageAbortBody), /* .memSize */ + UA_TRANSPORT_SECURECONVERSATIONMESSAGEABORTBODY, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + SecureConversationMessageAbortBody_members /* .members */ +}, +/* SecureConversationMessageFooter */ +{ + UA_TYPENAME("SecureConversationMessageFooter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_SecureConversationMessageFooter), /* .memSize */ + UA_TRANSPORT_SECURECONVERSATIONMESSAGEFOOTER, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + SecureConversationMessageFooter_members /* .members */ +}, +/* TcpHelloMessage */ +{ + UA_TYPENAME("TcpHelloMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_TcpHelloMessage), /* .memSize */ + UA_TRANSPORT_TCPHELLOMESSAGE, /* .typeIndex */ + 6, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + TcpHelloMessage_members /* .members */ +}, +/* TcpErrorMessage */ +{ + UA_TYPENAME("TcpErrorMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_TcpErrorMessage), /* .memSize */ + UA_TRANSPORT_TCPERRORMESSAGE, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + TcpErrorMessage_members /* .members */ +}, +/* MessageType */ +{ + UA_TYPENAME("MessageType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_MessageType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + MessageType_members /* .members */ +}, +/* AsymmetricAlgorithmSecurityHeader */ +{ + UA_TYPENAME("AsymmetricAlgorithmSecurityHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_AsymmetricAlgorithmSecurityHeader), /* .memSize */ + UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER, /* .typeIndex */ + 3, /* .membersSize */ + false, /* .builtin */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .binaryEncodingId */ + AsymmetricAlgorithmSecurityHeader_members /* .members */ +}, +/* TcpAcknowledgeMessage */ +{ + UA_TYPENAME("TcpAcknowledgeMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_TcpAcknowledgeMessage), /* .memSize */ + UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE, /* .typeIndex */ + 5, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) == (offsetof(UA_TcpAcknowledgeMessage, protocolVersion) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) == (offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) == (offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_TcpAcknowledgeMessage, maxChunkCount) == (offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) + sizeof(UA_UInt32)), /* .overlayable */ + 0, /* .binaryEncodingId */ + TcpAcknowledgeMessage_members /* .members */ +}, +/* SequenceHeader */ +{ + UA_TYPENAME("SequenceHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_SequenceHeader), /* .memSize */ + UA_TRANSPORT_SEQUENCEHEADER, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_SequenceHeader, requestId) == (offsetof(UA_SequenceHeader, sequenceNumber) + sizeof(UA_UInt32)), /* .overlayable */ + 0, /* .binaryEncodingId */ + SequenceHeader_members /* .members */ +}, +/* TcpMessageHeader */ +{ + UA_TYPENAME("TcpMessageHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_TcpMessageHeader), /* .memSize */ + UA_TRANSPORT_TCPMESSAGEHEADER, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_TcpMessageHeader, messageSize) == (offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) + sizeof(UA_UInt32)), /* .overlayable */ + 0, /* .binaryEncodingId */ + TcpMessageHeader_members /* .members */ +}, +/* ChunkType */ +{ + UA_TYPENAME("ChunkType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_ChunkType), /* .memSize */ + UA_TYPES_INT32, /* .typeIndex */ + 1, /* .membersSize */ + true, /* .builtin */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + ChunkType_members /* .members */ +}, +/* SymmetricAlgorithmSecurityHeader */ +{ + UA_TYPENAME("SymmetricAlgorithmSecurityHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_SymmetricAlgorithmSecurityHeader), /* .memSize */ + UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER, /* .typeIndex */ + 1, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .binaryEncodingId */ + SymmetricAlgorithmSecurityHeader_members /* .members */ +}, +/* SecureConversationMessageHeader */ +{ + UA_TYPENAME("SecureConversationMessageHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + sizeof(UA_SecureConversationMessageHeader), /* .memSize */ + UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER, /* .typeIndex */ + 2, /* .membersSize */ + false, /* .builtin */ + true, /* .pointerFree */ + true + && true + && UA_BINARY_OVERLAYABLE_INTEGER + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_TcpMessageHeader, messageSize) == (offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) + sizeof(UA_UInt32)) + && UA_BINARY_OVERLAYABLE_INTEGER + && offsetof(UA_SecureConversationMessageHeader, secureChannelId) == (offsetof(UA_SecureConversationMessageHeader, messageHeader) + sizeof(UA_TcpMessageHeader)), /* .overlayable */ + 0, /* .binaryEncodingId */ + SecureConversationMessageHeader_members /* .members */ +}, +}; + + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_statuscode_descriptions.c" ***********************************/ + +/********************************************************** + * Autogenerated -- do not modify + * Generated from /home/jvoe/open62541/tools/schema/Opc.Ua.StatusCodes.csv with script /home/jvoe/open62541/tools/generate_statuscode_descriptions.py + *********************************************************/ + + + +/* Definition for the deprecated StatusCode description API */ +const UA_StatusCodeDescription statusCodeExplanation_default = {0xffffffff, "", ""}; + +typedef struct { + UA_StatusCode code; + const char *name; +} UA_StatusCodeName; + +#ifndef UA_ENABLE_STATUSCODE_DESCRIPTIONS +static const char * emptyStatusCodeName = ""; +const char * UA_StatusCode_name(UA_StatusCode code) { + return emptyStatusCodeName; +} +#else +static const size_t statusCodeDescriptionsSize = 229; +static const UA_StatusCodeName statusCodeDescriptions[229] = { + {UA_STATUSCODE_GOOD, "Good"}, + + {UA_STATUSCODE_BADUNEXPECTEDERROR, "BadUnexpectedError"}, + {UA_STATUSCODE_BADINTERNALERROR, "BadInternalError"}, + {UA_STATUSCODE_BADOUTOFMEMORY, "BadOutOfMemory"}, + {UA_STATUSCODE_BADRESOURCEUNAVAILABLE, "BadResourceUnavailable"}, + {UA_STATUSCODE_BADCOMMUNICATIONERROR, "BadCommunicationError"}, + {UA_STATUSCODE_BADENCODINGERROR, "BadEncodingError"}, + {UA_STATUSCODE_BADDECODINGERROR, "BadDecodingError"}, + {UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED, "BadEncodingLimitsExceeded"}, + {UA_STATUSCODE_BADREQUESTTOOLARGE, "BadRequestTooLarge"}, + {UA_STATUSCODE_BADRESPONSETOOLARGE, "BadResponseTooLarge"}, + {UA_STATUSCODE_BADUNKNOWNRESPONSE, "BadUnknownResponse"}, + {UA_STATUSCODE_BADTIMEOUT, "BadTimeout"}, + {UA_STATUSCODE_BADSERVICEUNSUPPORTED, "BadServiceUnsupported"}, + {UA_STATUSCODE_BADSHUTDOWN, "BadShutdown"}, + {UA_STATUSCODE_BADSERVERNOTCONNECTED, "BadServerNotConnected"}, + {UA_STATUSCODE_BADSERVERHALTED, "BadServerHalted"}, + {UA_STATUSCODE_BADNOTHINGTODO, "BadNothingToDo"}, + {UA_STATUSCODE_BADTOOMANYOPERATIONS, "BadTooManyOperations"}, + {UA_STATUSCODE_BADTOOMANYMONITOREDITEMS, "BadTooManyMonitoredItems"}, + {UA_STATUSCODE_BADDATATYPEIDUNKNOWN, "BadDataTypeIdUnknown"}, + {UA_STATUSCODE_BADCERTIFICATEINVALID, "BadCertificateInvalid"}, + {UA_STATUSCODE_BADSECURITYCHECKSFAILED, "BadSecurityChecksFailed"}, + {UA_STATUSCODE_BADCERTIFICATETIMEINVALID, "BadCertificateTimeInvalid"}, + {UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID, "BadCertificateIssuerTimeInvalid"}, + {UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID, "BadCertificateHostNameInvalid"}, + {UA_STATUSCODE_BADCERTIFICATEURIINVALID, "BadCertificateUriInvalid"}, + {UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED, "BadCertificateUseNotAllowed"}, + {UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED, "BadCertificateIssuerUseNotAllowed"}, + {UA_STATUSCODE_BADCERTIFICATEUNTRUSTED, "BadCertificateUntrusted"}, + {UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN, "BadCertificateRevocationUnknown"}, + {UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN, "BadCertificateIssuerRevocationUnknown"}, + {UA_STATUSCODE_BADCERTIFICATEREVOKED, "BadCertificateRevoked"}, + {UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED, "BadCertificateIssuerRevoked"}, + {UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE, "BadCertificateChainIncomplete"}, + {UA_STATUSCODE_BADUSERACCESSDENIED, "BadUserAccessDenied"}, + {UA_STATUSCODE_BADIDENTITYTOKENINVALID, "BadIdentityTokenInvalid"}, + {UA_STATUSCODE_BADIDENTITYTOKENREJECTED, "BadIdentityTokenRejected"}, + {UA_STATUSCODE_BADSECURECHANNELIDINVALID, "BadSecureChannelIdInvalid"}, + {UA_STATUSCODE_BADINVALIDTIMESTAMP, "BadInvalidTimestamp"}, + {UA_STATUSCODE_BADNONCEINVALID, "BadNonceInvalid"}, + {UA_STATUSCODE_BADSESSIONIDINVALID, "BadSessionIdInvalid"}, + {UA_STATUSCODE_BADSESSIONCLOSED, "BadSessionClosed"}, + {UA_STATUSCODE_BADSESSIONNOTACTIVATED, "BadSessionNotActivated"}, + {UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID, "BadSubscriptionIdInvalid"}, + {UA_STATUSCODE_BADREQUESTHEADERINVALID, "BadRequestHeaderInvalid"}, + {UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID, "BadTimestampsToReturnInvalid"}, + {UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT, "BadRequestCancelledByClient"}, + {UA_STATUSCODE_BADTOOMANYARGUMENTS, "BadTooManyArguments"}, + {UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED, "GoodSubscriptionTransferred"}, + {UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY, "GoodCompletesAsynchronously"}, + {UA_STATUSCODE_GOODOVERLOAD, "GoodOverload"}, + {UA_STATUSCODE_GOODCLAMPED, "GoodClamped"}, + {UA_STATUSCODE_BADNOCOMMUNICATION, "BadNoCommunication"}, + {UA_STATUSCODE_BADWAITINGFORINITIALDATA, "BadWaitingForInitialData"}, + {UA_STATUSCODE_BADNODEIDINVALID, "BadNodeIdInvalid"}, + {UA_STATUSCODE_BADNODEIDUNKNOWN, "BadNodeIdUnknown"}, + {UA_STATUSCODE_BADATTRIBUTEIDINVALID, "BadAttributeIdInvalid"}, + {UA_STATUSCODE_BADINDEXRANGEINVALID, "BadIndexRangeInvalid"}, + {UA_STATUSCODE_BADINDEXRANGENODATA, "BadIndexRangeNoData"}, + {UA_STATUSCODE_BADDATAENCODINGINVALID, "BadDataEncodingInvalid"}, + {UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED, "BadDataEncodingUnsupported"}, + {UA_STATUSCODE_BADNOTREADABLE, "BadNotReadable"}, + {UA_STATUSCODE_BADNOTWRITABLE, "BadNotWritable"}, + {UA_STATUSCODE_BADOUTOFRANGE, "BadOutOfRange"}, + {UA_STATUSCODE_BADNOTSUPPORTED, "BadNotSupported"}, + {UA_STATUSCODE_BADNOTFOUND, "BadNotFound"}, + {UA_STATUSCODE_BADOBJECTDELETED, "BadObjectDeleted"}, + {UA_STATUSCODE_BADNOTIMPLEMENTED, "BadNotImplemented"}, + {UA_STATUSCODE_BADMONITORINGMODEINVALID, "BadMonitoringModeInvalid"}, + {UA_STATUSCODE_BADMONITOREDITEMIDINVALID, "BadMonitoredItemIdInvalid"}, + {UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID, "BadMonitoredItemFilterInvalid"}, + {UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED, "BadMonitoredItemFilterUnsupported"}, + {UA_STATUSCODE_BADFILTERNOTALLOWED, "BadFilterNotAllowed"}, + {UA_STATUSCODE_BADSTRUCTUREMISSING, "BadStructureMissing"}, + {UA_STATUSCODE_BADEVENTFILTERINVALID, "BadEventFilterInvalid"}, + {UA_STATUSCODE_BADCONTENTFILTERINVALID, "BadContentFilterInvalid"}, + {UA_STATUSCODE_BADFILTEROPERATORINVALID, "BadFilterOperatorInvalid"}, + {UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED, "BadFilterOperatorUnsupported"}, + {UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH, "BadFilterOperandCountMismatch"}, + {UA_STATUSCODE_BADFILTEROPERANDINVALID, "BadFilterOperandInvalid"}, + {UA_STATUSCODE_BADFILTERELEMENTINVALID, "BadFilterElementInvalid"}, + {UA_STATUSCODE_BADFILTERLITERALINVALID, "BadFilterLiteralInvalid"}, + {UA_STATUSCODE_BADCONTINUATIONPOINTINVALID, "BadContinuationPointInvalid"}, + {UA_STATUSCODE_BADNOCONTINUATIONPOINTS, "BadNoContinuationPoints"}, + {UA_STATUSCODE_BADREFERENCETYPEIDINVALID, "BadReferenceTypeIdInvalid"}, + {UA_STATUSCODE_BADBROWSEDIRECTIONINVALID, "BadBrowseDirectionInvalid"}, + {UA_STATUSCODE_BADNODENOTINVIEW, "BadNodeNotInView"}, + {UA_STATUSCODE_BADSERVERURIINVALID, "BadServerUriInvalid"}, + {UA_STATUSCODE_BADSERVERNAMEMISSING, "BadServerNameMissing"}, + {UA_STATUSCODE_BADDISCOVERYURLMISSING, "BadDiscoveryUrlMissing"}, + {UA_STATUSCODE_BADSEMPAHOREFILEMISSING, "BadSempahoreFileMissing"}, + {UA_STATUSCODE_BADREQUESTTYPEINVALID, "BadRequestTypeInvalid"}, + {UA_STATUSCODE_BADSECURITYMODEREJECTED, "BadSecurityModeRejected"}, + {UA_STATUSCODE_BADSECURITYPOLICYREJECTED, "BadSecurityPolicyRejected"}, + {UA_STATUSCODE_BADTOOMANYSESSIONS, "BadTooManySessions"}, + {UA_STATUSCODE_BADUSERSIGNATUREINVALID, "BadUserSignatureInvalid"}, + {UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID, "BadApplicationSignatureInvalid"}, + {UA_STATUSCODE_BADNOVALIDCERTIFICATES, "BadNoValidCertificates"}, + {UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED, "BadIdentityChangeNotSupported"}, + {UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST, "BadRequestCancelledByRequest"}, + {UA_STATUSCODE_BADPARENTNODEIDINVALID, "BadParentNodeIdInvalid"}, + {UA_STATUSCODE_BADREFERENCENOTALLOWED, "BadReferenceNotAllowed"}, + {UA_STATUSCODE_BADNODEIDREJECTED, "BadNodeIdRejected"}, + {UA_STATUSCODE_BADNODEIDEXISTS, "BadNodeIdExists"}, + {UA_STATUSCODE_BADNODECLASSINVALID, "BadNodeClassInvalid"}, + {UA_STATUSCODE_BADBROWSENAMEINVALID, "BadBrowseNameInvalid"}, + {UA_STATUSCODE_BADBROWSENAMEDUPLICATED, "BadBrowseNameDuplicated"}, + {UA_STATUSCODE_BADNODEATTRIBUTESINVALID, "BadNodeAttributesInvalid"}, + {UA_STATUSCODE_BADTYPEDEFINITIONINVALID, "BadTypeDefinitionInvalid"}, + {UA_STATUSCODE_BADSOURCENODEIDINVALID, "BadSourceNodeIdInvalid"}, + {UA_STATUSCODE_BADTARGETNODEIDINVALID, "BadTargetNodeIdInvalid"}, + {UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED, "BadDuplicateReferenceNotAllowed"}, + {UA_STATUSCODE_BADINVALIDSELFREFERENCE, "BadInvalidSelfReference"}, + {UA_STATUSCODE_BADREFERENCELOCALONLY, "BadReferenceLocalOnly"}, + {UA_STATUSCODE_BADNODELETERIGHTS, "BadNoDeleteRights"}, + {UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED, "UncertainReferenceNotDeleted"}, + {UA_STATUSCODE_BADSERVERINDEXINVALID, "BadServerIndexInvalid"}, + {UA_STATUSCODE_BADVIEWIDUNKNOWN, "BadViewIdUnknown"}, + {UA_STATUSCODE_BADVIEWTIMESTAMPINVALID, "BadViewTimestampInvalid"}, + {UA_STATUSCODE_BADVIEWPARAMETERMISMATCH, "BadViewParameterMismatch"}, + {UA_STATUSCODE_BADVIEWVERSIONINVALID, "BadViewVersionInvalid"}, + {UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE, "UncertainNotAllNodesAvailable"}, + {UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE, "GoodResultsMayBeIncomplete"}, + {UA_STATUSCODE_BADNOTTYPEDEFINITION, "BadNotTypeDefinition"}, + {UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER, "UncertainReferenceOutOfServer"}, + {UA_STATUSCODE_BADTOOMANYMATCHES, "BadTooManyMatches"}, + {UA_STATUSCODE_BADQUERYTOOCOMPLEX, "BadQueryTooComplex"}, + {UA_STATUSCODE_BADNOMATCH, "BadNoMatch"}, + {UA_STATUSCODE_BADMAXAGEINVALID, "BadMaxAgeInvalid"}, + {UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT, "BadSecurityModeInsufficient"}, + {UA_STATUSCODE_BADHISTORYOPERATIONINVALID, "BadHistoryOperationInvalid"}, + {UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED, "BadHistoryOperationUnsupported"}, + {UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT, "BadInvalidTimestampArgument"}, + {UA_STATUSCODE_BADWRITENOTSUPPORTED, "BadWriteNotSupported"}, + {UA_STATUSCODE_BADTYPEMISMATCH, "BadTypeMismatch"}, + {UA_STATUSCODE_BADMETHODINVALID, "BadMethodInvalid"}, + {UA_STATUSCODE_BADARGUMENTSMISSING, "BadArgumentsMissing"}, + {UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS, "BadTooManySubscriptions"}, + {UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS, "BadTooManyPublishRequests"}, + {UA_STATUSCODE_BADNOSUBSCRIPTION, "BadNoSubscription"}, + {UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN, "BadSequenceNumberUnknown"}, + {UA_STATUSCODE_BADMESSAGENOTAVAILABLE, "BadMessageNotAvailable"}, + {UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE, "BadInsufficientClientProfile"}, + {UA_STATUSCODE_BADSTATENOTACTIVE, "BadStateNotActive"}, + {UA_STATUSCODE_BADTCPSERVERTOOBUSY, "BadTcpServerTooBusy"}, + {UA_STATUSCODE_BADTCPMESSAGETYPEINVALID, "BadTcpMessageTypeInvalid"}, + {UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN, "BadTcpSecureChannelUnknown"}, + {UA_STATUSCODE_BADTCPMESSAGETOOLARGE, "BadTcpMessageTooLarge"}, + {UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES, "BadTcpNotEnoughResources"}, + {UA_STATUSCODE_BADTCPINTERNALERROR, "BadTcpInternalError"}, + {UA_STATUSCODE_BADTCPENDPOINTURLINVALID, "BadTcpEndpointUrlInvalid"}, + {UA_STATUSCODE_BADREQUESTINTERRUPTED, "BadRequestInterrupted"}, + {UA_STATUSCODE_BADREQUESTTIMEOUT, "BadRequestTimeout"}, + {UA_STATUSCODE_BADSECURECHANNELCLOSED, "BadSecureChannelClosed"}, + {UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN, "BadSecureChannelTokenUnknown"}, + {UA_STATUSCODE_BADSEQUENCENUMBERINVALID, "BadSequenceNumberInvalid"}, + {UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED, "BadProtocolVersionUnsupported"}, + {UA_STATUSCODE_BADCONFIGURATIONERROR, "BadConfigurationError"}, + {UA_STATUSCODE_BADNOTCONNECTED, "BadNotConnected"}, + {UA_STATUSCODE_BADDEVICEFAILURE, "BadDeviceFailure"}, + {UA_STATUSCODE_BADSENSORFAILURE, "BadSensorFailure"}, + {UA_STATUSCODE_BADOUTOFSERVICE, "BadOutOfService"}, + {UA_STATUSCODE_BADDEADBANDFILTERINVALID, "BadDeadbandFilterInvalid"}, + {UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE, "UncertainNoCommunicationLastUsableValue"}, + {UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE, "UncertainLastUsableValue"}, + {UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE, "UncertainSubstituteValue"}, + {UA_STATUSCODE_UNCERTAININITIALVALUE, "UncertainInitialValue"}, + {UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE, "UncertainSensorNotAccurate"}, + {UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED, "UncertainEngineeringUnitsExceeded"}, + {UA_STATUSCODE_UNCERTAINSUBNORMAL, "UncertainSubNormal"}, + {UA_STATUSCODE_GOODLOCALOVERRIDE, "GoodLocalOverride"}, + {UA_STATUSCODE_BADREFRESHINPROGRESS, "BadRefreshInProgress"}, + {UA_STATUSCODE_BADCONDITIONALREADYDISABLED, "BadConditionAlreadyDisabled"}, + {UA_STATUSCODE_BADCONDITIONALREADYENABLED, "BadConditionAlreadyEnabled"}, + {UA_STATUSCODE_BADCONDITIONDISABLED, "BadConditionDisabled"}, + {UA_STATUSCODE_BADEVENTIDUNKNOWN, "BadEventIdUnknown"}, + {UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE, "BadEventNotAcknowledgeable"}, + {UA_STATUSCODE_BADDIALOGNOTACTIVE, "BadDialogNotActive"}, + {UA_STATUSCODE_BADDIALOGRESPONSEINVALID, "BadDialogResponseInvalid"}, + {UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED, "BadConditionBranchAlreadyAcked"}, + {UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED, "BadConditionBranchAlreadyConfirmed"}, + {UA_STATUSCODE_BADCONDITIONALREADYSHELVED, "BadConditionAlreadyShelved"}, + {UA_STATUSCODE_BADCONDITIONNOTSHELVED, "BadConditionNotShelved"}, + {UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE, "BadShelvingTimeOutOfRange"}, + {UA_STATUSCODE_BADNODATA, "BadNoData"}, + {UA_STATUSCODE_BADBOUNDNOTFOUND, "BadBoundNotFound"}, + {UA_STATUSCODE_BADBOUNDNOTSUPPORTED, "BadBoundNotSupported"}, + {UA_STATUSCODE_BADDATALOST, "BadDataLost"}, + {UA_STATUSCODE_BADDATAUNAVAILABLE, "BadDataUnavailable"}, + {UA_STATUSCODE_BADENTRYEXISTS, "BadEntryExists"}, + {UA_STATUSCODE_BADNOENTRYEXISTS, "BadNoEntryExists"}, + {UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED, "BadTimestampNotSupported"}, + {UA_STATUSCODE_GOODENTRYINSERTED, "GoodEntryInserted"}, + {UA_STATUSCODE_GOODENTRYREPLACED, "GoodEntryReplaced"}, + {UA_STATUSCODE_UNCERTAINDATASUBNORMAL, "UncertainDataSubNormal"}, + {UA_STATUSCODE_GOODNODATA, "GoodNoData"}, + {UA_STATUSCODE_GOODMOREDATA, "GoodMoreData"}, + {UA_STATUSCODE_BADAGGREGATELISTMISMATCH, "BadAggregateListMismatch"}, + {UA_STATUSCODE_BADAGGREGATENOTSUPPORTED, "BadAggregateNotSupported"}, + {UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS, "BadAggregateInvalidInputs"}, + {UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED, "BadAggregateConfigurationRejected"}, + {UA_STATUSCODE_GOODDATAIGNORED, "GoodDataIgnored"}, + {UA_STATUSCODE_BADREQUESTNOTALLOWED, "BadRequestNotAllowed"}, + {UA_STATUSCODE_GOODEDITED, "GoodEdited"}, + {UA_STATUSCODE_GOODPOSTACTIONFAILED, "GoodPostActionFailed"}, + {UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED, "UncertainDominantValueChanged"}, + {UA_STATUSCODE_GOODDEPENDENTVALUECHANGED, "GoodDependentValueChanged"}, + {UA_STATUSCODE_BADDOMINANTVALUECHANGED, "BadDominantValueChanged"}, + {UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED, "UncertainDependentValueChanged"}, + {UA_STATUSCODE_BADDEPENDENTVALUECHANGED, "BadDependentValueChanged"}, + {UA_STATUSCODE_GOODCOMMUNICATIONEVENT, "GoodCommunicationEvent"}, + {UA_STATUSCODE_GOODSHUTDOWNEVENT, "GoodShutdownEvent"}, + {UA_STATUSCODE_GOODCALLAGAIN, "GoodCallAgain"}, + {UA_STATUSCODE_GOODNONCRITICALTIMEOUT, "GoodNonCriticalTimeout"}, + {UA_STATUSCODE_BADINVALIDARGUMENT, "BadInvalidArgument"}, + {UA_STATUSCODE_BADCONNECTIONREJECTED, "BadConnectionRejected"}, + {UA_STATUSCODE_BADDISCONNECT, "BadDisconnect"}, + {UA_STATUSCODE_BADCONNECTIONCLOSED, "BadConnectionClosed"}, + {UA_STATUSCODE_BADINVALIDSTATE, "BadInvalidState"}, + {UA_STATUSCODE_BADENDOFSTREAM, "BadEndOfStream"}, + {UA_STATUSCODE_BADNODATAAVAILABLE, "BadNoDataAvailable"}, + {UA_STATUSCODE_BADWAITINGFORRESPONSE, "BadWaitingForResponse"}, + {UA_STATUSCODE_BADOPERATIONABANDONED, "BadOperationAbandoned"}, + {UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK, "BadExpectedStreamToBlock"}, + {UA_STATUSCODE_BADWOULDBLOCK, "BadWouldBlock"}, + {UA_STATUSCODE_BADSYNTAXERROR, "BadSyntaxError"}, + {UA_STATUSCODE_BADMAXCONNECTIONSREACHED, "BadMaxConnectionsReached"}, + {0xffffffff, "Unknown StatusCode"} +}; + +const char * UA_StatusCode_name(UA_StatusCode code) { + for (size_t i = 0; i < statusCodeDescriptionsSize; ++i) { + if (statusCodeDescriptions[i].code == code) + return statusCodeDescriptions[i].name; + } + return statusCodeDescriptions[statusCodeDescriptionsSize-1].name; +} + +#endif + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014, 2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +size_t +UA_readNumber(u8 *buf, size_t buflen, u32 *number) { + UA_assert(buf); + UA_assert(number); + u32 n = 0; + size_t progress = 0; + /* read numbers until the end or a non-number character appears */ + while(progress < buflen) { + u8 c = buf[progress]; + if(c < '0' || c > '9') + break; + n = (n*10) + (u32)(c-'0'); + ++progress; + } + *number = n; + return progress; +} + +UA_StatusCode +UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, + u16 *outPort, UA_String *outPath) { + /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */ + if(endpointUrl->length < 11) { + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; + } else if (strncmp((char*)endpointUrl->data, "opc.tcp://", 10) != 0) { +#ifdef UA_ENABLE_PUBSUB + if (strncmp((char*)endpointUrl->data, "opc.udp://", 10) != 0) { + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; + } +#else + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; +#endif + } + + /* Where does the hostname end? */ + size_t curr = 10; + if(endpointUrl->data[curr] == '[') { + /* IPv6: opc.tcp://[2001:0db8:85a3::8a2e:0370:7334]:1234/path */ + for(; curr < endpointUrl->length; ++curr) { + if(endpointUrl->data[curr] == ']') + break; + } + if(curr == endpointUrl->length) + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; + curr++; + } else { + /* IPv4 or hostname: opc.tcp://something.something:1234/path */ + for(; curr < endpointUrl->length; ++curr) { + if(endpointUrl->data[curr] == ':' || endpointUrl->data[curr] == '/') + break; + } + } + + /* Set the hostname */ + outHostname->data = &endpointUrl->data[10]; + outHostname->length = curr - 10; + if(curr == endpointUrl->length) + return UA_STATUSCODE_GOOD; + + /* Set the port */ + if(endpointUrl->data[curr] == ':') { + if(++curr == endpointUrl->length) + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; + u32 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 */ + curr += progress; + if(curr == endpointUrl->length || endpointUrl->data[curr] == '/') + *outPort = (u16)largeNum; + if(curr == endpointUrl->length) + return UA_STATUSCODE_GOOD; + } + + /* Set the path */ + UA_assert(curr < endpointUrl->length); + if(endpointUrl->data[curr] != '/') + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; + if(++curr == endpointUrl->length) + return UA_STATUSCODE_GOOD; + outPath->data = &endpointUrl->data[curr]; + outPath->length = endpointUrl->length - curr; + + /* Remove trailing slash from the path */ + if(endpointUrl->data[endpointUrl->length - 1] == '/') + outPath->length--; + + return UA_STATUSCODE_GOOD; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +/* Only one thread operates on the repeated jobs. This is usually the "main" + * thread with the event loop. All other threads introduce changes via a + * multi-producer single-consumer (MPSC) queue. The queue is based on a design + * by Dmitry Vyukov. + * http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue + * + * The RepeatedCallback structure is used both in the sorted list of callbacks + * and in the MPSC changes queue. For the changes queue, we differentiate + * between three cases encoded in the callback pointer. + * + * callback > 0x01: add the new repeated callback to the sorted list + * callback == 0x00: remove the callback with the same id + * callback == 0x01: change the interval of the existing callback */ + +#define REMOVE_SENTINEL 0x00 +#define CHANGE_SENTINEL 0x01 + +struct UA_TimerCallbackEntry { + SLIST_ENTRY(UA_TimerCallbackEntry) next; /* Next element in the list */ + UA_DateTime nextTime; /* The next time when the callbacks + * are to be executed */ + UA_UInt64 interval; /* Interval in 100ns resolution */ + UA_UInt64 id; /* Id of the repeated callback */ + + UA_TimerCallback callback; + void *data; +}; + +void +UA_Timer_init(UA_Timer *t) { + SLIST_INIT(&t->repeatedCallbacks); + t->changes_head = (UA_TimerCallbackEntry*)&t->changes_stub; + t->changes_tail = (UA_TimerCallbackEntry*)&t->changes_stub; + t->changes_stub = NULL; + t->idCounter = 0; +} + +static void +enqueueChange(UA_Timer *t, UA_TimerCallbackEntry *tc) { + tc->next.sle_next = NULL; + UA_TimerCallbackEntry *prev = (UA_TimerCallbackEntry*) + UA_atomic_xchg((void * volatile *)&t->changes_head, tc); + /* Nothing can be dequeued while the producer is blocked here */ + prev->next.sle_next = tc; /* Once this change is visible in the consumer, + * the node is dequeued in the following + * iteration */ +} + +static UA_TimerCallbackEntry * +dequeueChange(UA_Timer *t) { + UA_TimerCallbackEntry *tail = t->changes_tail; + UA_TimerCallbackEntry *next = tail->next.sle_next; + if(tail == (UA_TimerCallbackEntry*)&t->changes_stub) { + if(!next) + return NULL; + t->changes_tail = next; + tail = next; + next = next->next.sle_next; + } + if(next) { + t->changes_tail = next; + return tail; + } + UA_TimerCallbackEntry* head = t->changes_head; + if(tail != head) + return NULL; + enqueueChange(t, (UA_TimerCallbackEntry*)&t->changes_stub); + next = tail->next.sle_next; + if(next) { + t->changes_tail = next; + return tail; + } + return NULL; +} + +/* Adding repeated callbacks: Add an entry with the "nextTime" timestamp in the + * future. This will be picked up in the next iteration and inserted at the + * correct place. So that the next execution takes place ät "nextTime". */ +UA_StatusCode +UA_Timer_addRepeatedCallback(UA_Timer *t, UA_TimerCallback callback, + void *data, UA_UInt32 interval, + UA_UInt64 *callbackId) { + /* A callback method needs to be present */ + if(!callback) + return UA_STATUSCODE_BADINTERNALERROR; + + /* The interval needs to be at least 5ms */ + if(interval < 5) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Allocate the repeated callback structure */ + UA_TimerCallbackEntry *tc = + (UA_TimerCallbackEntry*)UA_malloc(sizeof(UA_TimerCallbackEntry)); + if(!tc) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Set the repeated callback */ + tc->interval = (UA_UInt64)interval * UA_DATETIME_MSEC; + tc->id = ++t->idCounter; + tc->callback = callback; + tc->data = data; + tc->nextTime = UA_DateTime_nowMonotonic() + (UA_DateTime)tc->interval; + + /* Set the output identifier */ + if(callbackId) + *callbackId = tc->id; + + /* Enqueue the changes in the MPSC queue */ + enqueueChange(t, tc); + return UA_STATUSCODE_GOOD; +} + +static void +addTimerCallbackEntry(UA_Timer *t, UA_TimerCallbackEntry * UA_RESTRICT tc) { + /* Find the last entry before this callback */ + UA_TimerCallbackEntry *tmpTc, *afterTc = NULL; + SLIST_FOREACH(tmpTc, &t->repeatedCallbacks, next) { + if(tmpTc->nextTime >= tc->nextTime) + break; + + /* The goal is to have many repeated callbacks with the same repetition + * interval in a "block" in order to reduce linear search for re-entry + * to the sorted list after processing. Allow the first execution to lie + * between "nextTime - 1s" and "nextTime" if this adjustment groups + * callbacks with the same repetition interval. + * Callbacks of a block are added in reversed order. This design allows + * the monitored items of a subscription (if created in a sequence with the + * same publish/sample interval) to be executed before the subscription + * publish the notifications */ + if(tmpTc->interval == tc->interval && + tmpTc->nextTime > (tc->nextTime - UA_DATETIME_SEC)) { + tc->nextTime = tmpTc->nextTime; + break; + } + + /* tc is neither in the same interval nor supposed to be executed sooner + * than tmpTc. Update afterTc to push tc further back in the timer list. */ + afterTc = tmpTc; + } + + /* Add the repeated callback */ + if(afterTc) + SLIST_INSERT_AFTER(afterTc, tc, next); + else + SLIST_INSERT_HEAD(&t->repeatedCallbacks, tc, next); +} + +UA_StatusCode +UA_Timer_changeRepeatedCallbackInterval(UA_Timer *t, UA_UInt64 callbackId, + UA_UInt32 interval) { + /* The interval needs to be at least 5ms */ + if(interval < 5) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Allocate the repeated callback structure */ + UA_TimerCallbackEntry *tc = + (UA_TimerCallbackEntry*)UA_malloc(sizeof(UA_TimerCallbackEntry)); + if(!tc) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Set the repeated callback */ + tc->interval = (UA_UInt64)interval * UA_DATETIME_MSEC; + tc->id = callbackId; + tc->nextTime = UA_DateTime_nowMonotonic() + (UA_DateTime)tc->interval; + tc->callback = (UA_TimerCallback)CHANGE_SENTINEL; + + /* Enqueue the changes in the MPSC queue */ + enqueueChange(t, tc); + return UA_STATUSCODE_GOOD; +} + +static void +changeTimerCallbackEntryInterval(UA_Timer *t, UA_UInt64 callbackId, + UA_UInt64 interval, UA_DateTime nextTime) { + /* Remove from the sorted list */ + UA_TimerCallbackEntry *tc, *prev = NULL; + SLIST_FOREACH(tc, &t->repeatedCallbacks, next) { + if(callbackId == tc->id) { + if(prev) + SLIST_REMOVE_AFTER(prev, next); + else + SLIST_REMOVE_HEAD(&t->repeatedCallbacks, next); + break; + } + prev = tc; + } + if(!tc) + return; + + /* Adjust settings */ + tc->interval = interval; + tc->nextTime = nextTime; + + /* Reinsert at the new position */ + addTimerCallbackEntry(t, tc); +} + +/* Removing a repeated callback: Add an entry with the "nextTime" timestamp set + * to UA_INT64_MAX. The next iteration picks this up and removes the repated + * callback from the linked list. */ +UA_StatusCode +UA_Timer_removeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId) { + /* Allocate the repeated callback structure */ + UA_TimerCallbackEntry *tc = + (UA_TimerCallbackEntry*)UA_malloc(sizeof(UA_TimerCallbackEntry)); + if(!tc) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Set the repeated callback with the sentinel nextTime */ + tc->id = callbackId; + tc->callback = (UA_TimerCallback)REMOVE_SENTINEL; + + /* Enqueue the changes in the MPSC queue */ + enqueueChange(t, tc); + return UA_STATUSCODE_GOOD; +} + +static void +removeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId) { + UA_TimerCallbackEntry *tc, *prev = NULL; + SLIST_FOREACH(tc, &t->repeatedCallbacks, next) { + if(callbackId == tc->id) { + if(prev) + SLIST_REMOVE_AFTER(prev, next); + else + SLIST_REMOVE_HEAD(&t->repeatedCallbacks, next); + UA_free(tc); + break; + } + prev = tc; + } +} + +/* Process the changes that were added to the MPSC queue (by other threads) */ +static void +processChanges(UA_Timer *t) { + UA_TimerCallbackEntry *change; + while((change = dequeueChange(t))) { + switch((uintptr_t)change->callback) { + case REMOVE_SENTINEL: + removeRepeatedCallback(t, change->id); + UA_free(change); + break; + case CHANGE_SENTINEL: + changeTimerCallbackEntryInterval(t, change->id, change->interval, + change->nextTime); + UA_free(change); + break; + default: + addTimerCallbackEntry(t, change); + } + } +} + +UA_DateTime +UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic, + UA_TimerDispatchCallback dispatchCallback, + void *application) { + /* Insert and remove callbacks */ + processChanges(t); + + /* Find the last callback to be executed now */ + UA_TimerCallbackEntry *firstAfter, *lastNow = NULL; + SLIST_FOREACH(firstAfter, &t->repeatedCallbacks, next) { + if(firstAfter->nextTime > nowMonotonic) + break; + lastNow = firstAfter; + } + + /* Nothing to do */ + if(!lastNow) { + if(firstAfter) + return firstAfter->nextTime; + return UA_INT64_MAX; + } + + /* Put the callbacks that are executed now in a separate list */ + UA_TimerCallbackList executedNowList; + executedNowList.slh_first = SLIST_FIRST(&t->repeatedCallbacks); + lastNow->next.sle_next = NULL; + + /* Fake entry to represent the first element in the newly-sorted list */ + UA_TimerCallbackEntry tmp_first; + tmp_first.nextTime = nowMonotonic - 1; /* never matches for last_dispatched */ + tmp_first.next.sle_next = firstAfter; + UA_TimerCallbackEntry *last_dispatched = &tmp_first; + + /* Iterate over the list of callbacks to process now */ + UA_TimerCallbackEntry *tc; + while((tc = SLIST_FIRST(&executedNowList))) { + /* Remove from the list */ + SLIST_REMOVE_HEAD(&executedNowList, next); + + /* Dispatch/process callback */ + dispatchCallback(application, tc->callback, tc->data); + + /* Set the time for the next execution. Prevent an infinite loop by + * forcing the next processing into the next iteration. */ + tc->nextTime += (UA_Int64)tc->interval; + if(tc->nextTime < nowMonotonic) + tc->nextTime = nowMonotonic + 1; + + /* Find the new position for tc to keep the list sorted */ + UA_TimerCallbackEntry *prev_tc; + if(last_dispatched->nextTime == tc->nextTime) { + /* We try to "batch" repeatedCallbacks with the same interval. This + * saves a linear search when the last dispatched entry has the same + * nextTime timestamp as this entry. */ + UA_assert(last_dispatched != &tmp_first); + prev_tc = last_dispatched; + } else { + /* Find the position for the next execution by a linear search + * starting at last_dispatched or the first element */ + if(last_dispatched->nextTime < tc->nextTime) + prev_tc = last_dispatched; + else + prev_tc = &tmp_first; + + while(true) { + UA_TimerCallbackEntry *n = SLIST_NEXT(prev_tc, next); + if(!n || n->nextTime >= tc->nextTime) + break; + prev_tc = n; + } + } + + /* Update last_dispatched to make sure batched callbacks are added in the + * same sequence as before they were executed and to save some iterations + * of the linear search for callbacks to be added further back in the list. */ + last_dispatched = tc; + + /* Add entry to the new position in the sorted list */ + SLIST_INSERT_AFTER(prev_tc, tc, next); + } + + /* Set the entry-point for the newly sorted list */ + t->repeatedCallbacks.slh_first = tmp_first.next.sle_next; + + /* Re-repeat processAddRemoved since one of the callbacks might have removed + * or added a callback. So we return a correct timeout. */ + processChanges(t); + + /* Return timestamp of next repetition */ + tc = SLIST_FIRST(&t->repeatedCallbacks); + if(!tc) + return UA_INT64_MAX; /* Main-loop has a max timeout / will continue earlier */ + return tc->nextTime; +} + +void +UA_Timer_deleteMembers(UA_Timer *t) { + /* Process changes to empty the MPSC queue */ + processChanges(t); + + /* Remove repeated callbacks */ + UA_TimerCallbackEntry *current; + while((current = SLIST_FIRST(&t->repeatedCallbacks))) { + SLIST_REMOVE_HEAD(&t->repeatedCallbacks, next); + UA_free(current); + } +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2016-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +void UA_Connection_deleteMembers(UA_Connection *connection) { + UA_ByteString_deleteMembers(&connection->incompleteMessage); +} + +/* Hides somme errors before sending them to a client according to the + * standard. */ +static void +hideErrors(UA_TcpErrorMessage *const error) { + switch(error->error) { + case UA_STATUSCODE_BADCERTIFICATEUNTRUSTED: + error->error = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + error->reason = UA_STRING_NULL; + break; + // TODO: Check if these are all cases that need to be covered. + default: + break; + } +} + +void +UA_Connection_sendError(UA_Connection *connection, UA_TcpErrorMessage *error) { + hideErrors(error); + + UA_TcpMessageHeader header; + header.messageTypeAndChunkType = UA_MESSAGETYPE_ERR + UA_CHUNKTYPE_FINAL; + // Header + ErrorMessage (error + reasonLength_field + length) + header.messageSize = 8 + (4 + 4 + (UA_UInt32)error->reason.length); + + /* Get the send buffer from the network layer */ + UA_ByteString msg = UA_BYTESTRING_NULL; + UA_StatusCode retval = connection->getSendBuffer(connection, header.messageSize, &msg); + if(retval != UA_STATUSCODE_GOOD) + return; + + /* 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); + msg.length = header.messageSize; + connection->send(connection, &msg); +} + +static UA_StatusCode +prependIncompleteChunk(UA_Connection *connection, UA_ByteString *message) { + /* Allocate the new message buffer */ + size_t length = connection->incompleteMessage.length + message->length; + UA_Byte *data = (UA_Byte*)UA_realloc(connection->incompleteMessage.data, length); + if(!data) { + UA_ByteString_deleteMembers(&connection->incompleteMessage); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Copy / release the current message buffer */ + memcpy(&data[connection->incompleteMessage.length], message->data, message->length); + message->length = length; + message->data = data; + connection->incompleteMessage = UA_BYTESTRING_NULL; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +bufferIncompleteChunk(UA_Connection *connection, const UA_Byte *pos, const UA_Byte *end) { + size_t length = (uintptr_t)end - (uintptr_t)pos; + UA_StatusCode retval = UA_ByteString_allocBuffer(&connection->incompleteMessage, length); + if(retval != UA_STATUSCODE_GOOD) + return retval; + memcpy(connection->incompleteMessage.data, pos, length); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +processChunk(UA_Connection *connection, void *application, + UA_Connection_processChunk processCallback, + const UA_Byte **posp, const UA_Byte *end, UA_Boolean *done) { + const UA_Byte *pos = *posp; + size_t length = (uintptr_t)end - (uintptr_t)pos; + + /* At least 8 byte needed for the header. Wait for the next chunk. */ + if(length < 8) { + bufferIncompleteChunk(connection, pos, end); + *done = true; + return UA_STATUSCODE_GOOD; + } + + /* Check the message type */ + UA_MessageType msgtype = (UA_MessageType)((UA_UInt32)pos[0] + ((UA_UInt32)pos[1] << 8) + + ((UA_UInt32)pos[2] << 16)); + if(msgtype != UA_MESSAGETYPE_MSG && msgtype != UA_MESSAGETYPE_ERR && + msgtype != UA_MESSAGETYPE_OPN && msgtype != UA_MESSAGETYPE_HEL && + msgtype != UA_MESSAGETYPE_ACK && msgtype != UA_MESSAGETYPE_CLO) { + /* The message type is not recognized */ + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + + UA_Byte isFinal = pos[3]; + if(isFinal != 'C' && isFinal != 'F' && isFinal != 'A') { + /* The message type is not recognized */ + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + + UA_UInt32 chunk_length = 0; + UA_ByteString temp = { 8, (UA_Byte*)(uintptr_t)pos }; /* At least 8 byte left */ + size_t temp_offset = 4; + /* Decoding the UInt32 cannot fail */ + UA_UInt32_decodeBinary(&temp, &temp_offset, &chunk_length); + + /* The message size is not allowed */ + if(chunk_length < 16 || chunk_length > connection->localConf.recvBufferSize) + return UA_STATUSCODE_BADTCPMESSAGETOOLARGE; + + /* Wait for the next packet to process the complete chunk */ + if(chunk_length > length) { + bufferIncompleteChunk(connection, pos, end); + *done = true; + return UA_STATUSCODE_GOOD; + } + + /* Set pendingMessage if there is a message after this message */ + if(length > chunk_length) + connection->pendingMessage = true; + + /* Process the chunk; forward the position pointer */ + temp.length = chunk_length; + *posp += chunk_length; + *done = false; + return processCallback(application, connection, &temp); +} + +UA_StatusCode +UA_Connection_processChunks(UA_Connection *connection, void *application, + UA_Connection_processChunk processCallback, + const UA_ByteString *packet) { + /* If we have stored an incomplete chunk, prefix to the received message. + * After this block, connection->incompleteMessage is always empty. The + * message and the buffer is released if allocating the memory fails. */ + UA_Boolean realloced = false; + UA_ByteString message = *packet; + UA_StatusCode retval; + if(connection->incompleteMessage.length > 0) { + retval = prependIncompleteChunk(connection, &message); + if(retval != UA_STATUSCODE_GOOD) + return retval; + realloced = true; + } + + /* Loop over the received chunks. pos is increased with each chunk. */ + const UA_Byte *pos = message.data; + const UA_Byte *end = &message.data[message.length]; + UA_Boolean done = true; + do { + retval = processChunk(connection, application, processCallback, + &pos, end, &done); + connection->pendingMessage = false; + } while(!done && retval == UA_STATUSCODE_GOOD); + + if(realloced) + UA_ByteString_deleteMembers(&message); + return retval; +} + +/* In order to know whether a chunk was processed, we insert an indirection into + * the callback. */ +struct completeChunkTrampolineData { + UA_Boolean called; + void *application; + UA_Connection_processChunk processCallback; +}; + +static UA_StatusCode +completeChunkTrampoline(void *application, UA_Connection *connection, + UA_ByteString *chunk) { + struct completeChunkTrampolineData *data = + (struct completeChunkTrampolineData*)application; + data->called = true; + return data->processCallback(data->application, connection, chunk); +} + +UA_StatusCode +UA_Connection_receiveChunksBlocking(UA_Connection *connection, void *application, + UA_Connection_processChunk processCallback, + UA_UInt32 timeout) { + UA_DateTime now = UA_DateTime_nowMonotonic(); + UA_DateTime maxDate = now + (timeout * UA_DATETIME_MSEC); + + struct completeChunkTrampolineData data; + data.called = false; + data.application = application; + data.processCallback = processCallback; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + while(true) { + /* Listen for messages to arrive */ + UA_ByteString packet = UA_BYTESTRING_NULL; + retval = connection->recv(connection, &packet, timeout); + if(retval != UA_STATUSCODE_GOOD) + break; + + /* Try to process one complete chunk */ + retval = UA_Connection_processChunks(connection, &data, + completeChunkTrampoline, &packet); + connection->releaseRecvBuffer(connection, &packet); + if(data.called) + break; + + /* We received a message. But the chunk is incomplete. Compute the + * remaining timeout. */ + now = UA_DateTime_nowMonotonic(); + + /* >= avoid timeout to be set to 0 */ + if(now >= maxDate) + return UA_STATUSCODE_GOODNONCRITICALTIMEOUT; + + /* round always to upper value to avoid timeout to be set to 0 + * if(maxDate - now) < (UA_DATETIME_MSEC/2) */ + timeout = (UA_UInt32)(((maxDate - now) + (UA_DATETIME_MSEC - 1)) / UA_DATETIME_MSEC); + } + return retval; +} + +void UA_Connection_detachSecureChannel(UA_Connection *connection) { + UA_SecureChannel *channel = connection->channel; + if(channel) + /* only replace when the channel points to this connection */ + UA_atomic_cmpxchg((void**)&channel->connection, connection, NULL); + UA_atomic_xchg((void**)&connection->channel, NULL); +} + +// TODO: Return an error code +void +UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) { + if(UA_atomic_cmpxchg((void**)&channel->connection, NULL, connection) == NULL) + UA_atomic_xchg((void**)&connection->channel, (void*)channel); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2016-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016 (c) TorbenD + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#define UA_BITMASK_MESSAGETYPE 0x00ffffff +#define UA_BITMASK_CHUNKTYPE 0xff000000 +#define UA_ASYMMETRIC_ALG_SECURITY_HEADER_FIXED_LENGTH 12 +#define UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH 4 +#define UA_SEQUENCE_HEADER_LENGTH 8 +#define UA_SECUREMH_AND_SYMALGH_LENGTH \ + (UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + \ + UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH) + +const UA_ByteString + UA_SECURITY_POLICY_NONE_URI = {47, (UA_Byte *)"http://opcfoundation.org/UA/SecurityPolicy#None"}; + +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS +UA_StatusCode decrypt_verifySignatureFailure; +UA_StatusCode sendAsym_sendFailure; +UA_StatusCode processSym_seqNumberFailure; +#endif + +UA_StatusCode +UA_SecureChannel_init(UA_SecureChannel *channel, + const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate) { + if(channel == NULL || securityPolicy == NULL || remoteCertificate == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Linked lists are also initialized by zeroing out */ + memset(channel, 0, sizeof(UA_SecureChannel)); + channel->state = UA_SECURECHANNELSTATE_FRESH; + channel->securityPolicy = securityPolicy; + + UA_StatusCode retval; + if(channel->securityPolicy->certificateVerification != NULL) { + retval = channel->securityPolicy->certificateVerification-> + verifyCertificate(channel->securityPolicy->certificateVerification->context, remoteCertificate); + + if(retval != UA_STATUSCODE_GOOD) + return retval; + } else { + UA_LOG_WARNING(channel->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, "No PKI plugin set. " + "Accepting all certificates"); + } + + retval = securityPolicy->channelModule. + newContext(securityPolicy, remoteCertificate, &channel->channelContext); + if(retval != UA_STATUSCODE_GOOD) + 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. + makeCertificateThumbprint(securityPolicy, &channel->remoteCertificate, + &remoteCertificateThumbprint); + + return retval; +} + +void +UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel) { + /* Delete members */ + UA_ByteString_deleteMembers(&channel->remoteCertificate); + UA_ByteString_deleteMembers(&channel->localNonce); + UA_ByteString_deleteMembers(&channel->remoteNonce); + UA_ChannelSecurityToken_deleteMembers(&channel->securityToken); + UA_ChannelSecurityToken_deleteMembers(&channel->nextSecurityToken); + + /* Delete the channel context for the security policy */ + if(channel->securityPolicy) + channel->securityPolicy->channelModule.deleteContext(channel->channelContext); + + /* Detach from the connection and close the connection */ + if(channel->connection) { + if(channel->connection->state != UA_CONNECTION_CLOSED) + channel->connection->close(channel->connection); + UA_Connection_detachSecureChannel(channel->connection); + } + + /* Remove session pointers (not the sessions) and NULL the pointers back to + * the SecureChannel in the Session */ + UA_SessionHeader *sh, *temp; + LIST_FOREACH_SAFE(sh, &channel->sessions, pointers, temp) { + sh->channel = NULL; + LIST_REMOVE(sh, pointers); + } + + /* Remove the buffered chunks */ + struct MessageEntry *me, *temp_me; + LIST_FOREACH_SAFE(me, &channel->chunks, pointers, temp_me) { + struct ChunkPayload *cp, *temp_cp; + SIMPLEQ_FOREACH_SAFE(cp, &me->chunkPayload, pointers, temp_cp) { + UA_ByteString_deleteMembers(&cp->bytes); + UA_free(cp); + } + LIST_REMOVE(me, pointers); + UA_free(me); + } +} + +UA_StatusCode +UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel) { + if(!channel->securityPolicy) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Is the length of the previous nonce correct? */ + size_t nonceLength = channel->securityPolicy->symmetricModule.secureChannelNonceLength; + if(channel->localNonce.length != nonceLength) { + UA_ByteString_deleteMembers(&channel->localNonce); + UA_StatusCode retval = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + return channel->securityPolicy->symmetricModule. + generateNonce(channel->securityPolicy, &channel->localNonce); +} + +static UA_StatusCode +UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *const channel, + const UA_SecurityPolicy *const securityPolicy) { + const UA_SecurityPolicyChannelModule *channelModule = &securityPolicy->channelModule; + const UA_SecurityPolicySymmetricModule *symmetricModule = &securityPolicy->symmetricModule; + const UA_SecurityPolicyCryptoModule *const cryptoModule = &securityPolicy->symmetricModule.cryptoModule; + /* Symmetric key length */ + size_t encryptionKeyLength = + cryptoModule->encryptionAlgorithm.getLocalKeyLength(securityPolicy, channel->channelContext); + size_t encryptionBlockSize = + cryptoModule->encryptionAlgorithm.getLocalBlockSize(securityPolicy, channel->channelContext); + size_t signingKeyLength = + cryptoModule->signatureAlgorithm.getLocalKeyLength(securityPolicy, channel->channelContext); + const size_t bufSize = encryptionBlockSize + signingKeyLength + encryptionKeyLength; + UA_STACKARRAY(UA_Byte, bufBytes, bufSize); + UA_ByteString buffer = {bufSize, bufBytes}; + + /* Local keys */ + UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->remoteNonce, + &channel->localNonce, &buffer); + if(retval != UA_STATUSCODE_GOOD) + return retval; + const UA_ByteString localSigningKey = {signingKeyLength, buffer.data}; + const UA_ByteString localEncryptingKey = {encryptionKeyLength, + buffer.data + signingKeyLength}; + const UA_ByteString localIv = {encryptionBlockSize, + buffer.data + signingKeyLength + + encryptionKeyLength}; + retval = channelModule->setLocalSymSigningKey(channel->channelContext, &localSigningKey); + retval |= channelModule->setLocalSymEncryptingKey(channel->channelContext, &localEncryptingKey); + retval |= channelModule->setLocalSymIv(channel->channelContext, &localIv); + return retval; +} + +static UA_StatusCode +UA_SecureChannel_generateRemoteKeys(const UA_SecureChannel *const channel, + const UA_SecurityPolicy *const securityPolicy) { + const UA_SecurityPolicyChannelModule *channelModule = &securityPolicy->channelModule; + const UA_SecurityPolicySymmetricModule *symmetricModule = &securityPolicy->symmetricModule; + const UA_SecurityPolicyCryptoModule *const cryptoModule = &securityPolicy->symmetricModule.cryptoModule; + /* Symmetric key length */ + size_t encryptionKeyLength = + cryptoModule->encryptionAlgorithm.getRemoteKeyLength(securityPolicy, channel->channelContext); + size_t encryptionBlockSize = + cryptoModule->encryptionAlgorithm.getRemoteBlockSize(securityPolicy, channel->channelContext); + size_t signingKeyLength = + cryptoModule->signatureAlgorithm.getRemoteKeyLength(securityPolicy, channel->channelContext); + const size_t bufSize = encryptionBlockSize + signingKeyLength + encryptionKeyLength; + UA_STACKARRAY(UA_Byte, bufBytes, bufSize); + UA_ByteString buffer = {bufSize, bufBytes}; + + /* Remote keys */ + UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->localNonce, + &channel->remoteNonce, &buffer); + if(retval != UA_STATUSCODE_GOOD) + return retval; + const UA_ByteString remoteSigningKey = {signingKeyLength, buffer.data}; + const UA_ByteString remoteEncryptingKey = {encryptionKeyLength, + buffer.data + signingKeyLength}; + const UA_ByteString remoteIv = {encryptionBlockSize, + buffer.data + signingKeyLength + + encryptionKeyLength}; + retval = channelModule->setRemoteSymSigningKey(channel->channelContext, &remoteSigningKey); + retval |= channelModule->setRemoteSymEncryptingKey(channel->channelContext, &remoteEncryptingKey); + retval |= channelModule->setRemoteSymIv(channel->channelContext, &remoteIv); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + return retval; +} + +UA_StatusCode +UA_SecureChannel_generateNewKeys(UA_SecureChannel *channel) { + UA_StatusCode retval = UA_SecureChannel_generateLocalKeys(channel, channel->securityPolicy); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + retval = UA_SecureChannel_generateRemoteKeys(channel, channel->securityPolicy); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + return retval; +} + +UA_SessionHeader * +UA_SecureChannel_getSession(UA_SecureChannel *channel, + const UA_NodeId *authenticationToken) { + struct UA_SessionHeader *sh; + LIST_FOREACH(sh, &channel->sessions, pointers) { + if(UA_NodeId_equal(&sh->authenticationToken, authenticationToken)) + break; + } + return sh; +} + +UA_StatusCode +UA_SecureChannel_revolveTokens(UA_SecureChannel *channel) { + if(channel->nextSecurityToken.tokenId == 0) // no security token issued + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; + + + //FIXME: not thread-safe ???? Why is this not thread safe? + UA_ChannelSecurityToken_deleteMembers(&channel->previousSecurityToken); + UA_ChannelSecurityToken_copy(&channel->securityToken, &channel->previousSecurityToken); + + UA_ChannelSecurityToken_deleteMembers(&channel->securityToken); + UA_ChannelSecurityToken_copy(&channel->nextSecurityToken, &channel->securityToken); + + UA_ChannelSecurityToken_deleteMembers(&channel->nextSecurityToken); + UA_ChannelSecurityToken_init(&channel->nextSecurityToken); + return UA_SecureChannel_generateNewKeys(channel); +} +/***************************/ +/* Send Asymmetric Message */ +/***************************/ + +static UA_UInt16 +calculatePaddingAsym(const UA_SecurityPolicy *securityPolicy, const void *channelContext, + size_t bytesToWrite, UA_Byte *paddingSize, UA_Byte *extraPaddingSize) { + size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemotePlainTextBlockSize(securityPolicy, channelContext); + size_t signatureSize = securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, channelContext); + size_t paddingBytes = 1; + if(securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteKeyLength(securityPolicy, channelContext) > 2048) + ++paddingBytes; + size_t padding = (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) % + plainTextBlockSize)); + *paddingSize = (UA_Byte)(padding & 0xff); + *extraPaddingSize = (UA_Byte)(padding >> 8); + return (UA_UInt16)padding; +} + +static size_t +calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel) { + size_t asymHeaderLength = UA_ASYMMETRIC_ALG_SECURITY_HEADER_FIXED_LENGTH + + channel->securityPolicy->policyUri.length; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + /* OPN is always encrypted even if mode sign only */ + asymHeaderLength += 20; /* Thumbprints are always 20 byte long */ + asymHeaderLength += channel->securityPolicy->localCertificate.length; + } + return asymHeaderLength; +} + +static void +hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, const UA_Byte **buf_end) { + const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; + *buf_start += UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + UA_SEQUENCE_HEADER_LENGTH; + + /* Add the SecurityHeaderLength */ + *buf_start += calculateAsymAlgSecurityHeaderLength(channel); + size_t potentialEncryptionMaxSize = (size_t)(*buf_end - *buf_start) + UA_SEQUENCE_HEADER_LENGTH; + + /* Hide bytes for signature and padding */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + *buf_end -= securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, channel->channelContext); + *buf_end -= 2; /* padding byte and extraPadding byte */ + + /* Add some overhead length due to RSA implementations adding a signature themselves */ + *buf_end -= UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(securityPolicy, + channel->channelContext, + potentialEncryptionMaxSize); + } +} + +/* Sends an OPN message using asymmetric encryption if defined */ +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; + + const UA_SecurityPolicy *const securityPolicy = channel->securityPolicy; + UA_Connection *connection = channel->connection; + if(!connection) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Allocate the message buffer */ + UA_ByteString buf = UA_BYTESTRING_NULL; + UA_StatusCode retval = + connection->getSendBuffer(connection, connection->localConf.sendBufferSize, &buf); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Restrict buffer to the available space for the payload */ + UA_Byte *buf_pos = buf.data; + const UA_Byte *buf_end = &buf.data[buf.length]; + 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; + } + + /* Compute the length of the asym header */ + const size_t securityHeaderLength = calculateAsymAlgSecurityHeaderLength(channel); + + /* Pad the message. Also if securitymode is only sign, 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) { + 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; + UA_Byte paddingSize = 0; + UA_Byte extraPaddingSize = 0; + UA_UInt16 totalPaddingSize = + calculatePaddingAsym(securityPolicy, channel->channelContext, + bytesToWrite, &paddingSize, &extraPaddingSize); + + // This is <= because the paddingSize byte also has to be written. + for(UA_UInt16 i = 0; i <= totalPaddingSize; ++i) { + *buf_pos = paddingSize; + ++buf_pos; + } + if(securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteKeyLength(securityPolicy, channel->channelContext) > 2048) { + *buf_pos = extraPaddingSize; + ++buf_pos; + } + } + + /* The total message length */ + size_t pre_sig_length = (uintptr_t)buf_pos - (uintptr_t)buf.data; + size_t total_length = pre_sig_length; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + total_length += securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, channel->channelContext); + + /* Encode the headers at the beginning of the message */ + UA_Byte *header_pos = buf.data; + size_t dataToEncryptLength = + total_length - (UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH + securityHeaderLength); + UA_SecureConversationMessageHeader respHeader; + respHeader.messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL; + respHeader.messageHeader.messageSize = (UA_UInt32) + (total_length + UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(securityPolicy, + channel->channelContext, + dataToEncryptLength)); + respHeader.secureChannelId = channel->securityToken.channelId; + retval = UA_encodeBinary(&respHeader, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER], + &header_pos, &buf_end, NULL, NULL); + + UA_AsymmetricAlgorithmSecurityHeader asymHeader; + UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); + asymHeader.securityPolicyUri = channel->securityPolicy->policyUri; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + asymHeader.senderCertificate = channel->securityPolicy->localCertificate; + asymHeader.receiverCertificateThumbprint.length = 20; + asymHeader.receiverCertificateThumbprint.data = channel->remoteCertificateThumbprint; + } + retval |= UA_encodeBinary(&asymHeader, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], + &header_pos, &buf_end, NULL, NULL); + + 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); + + /* Did encoding the header succeed? */ + if(retval != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(connection, &buf); + return retval; + } + + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + /* Sign message */ + const UA_ByteString dataToSign = {pre_sig_length, buf.data}; + size_t sigsize = securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, channel->channelContext); + UA_ByteString signature = {sigsize, buf.data + pre_sig_length}; + retval = securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm. + sign(securityPolicy, channel->channelContext, &dataToSign, &signature); + if(retval != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(connection, &buf); + 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_ByteString dataToEncrypt = {total_length - unencrypted_length, + &buf.data[unencrypted_length]}; + retval = securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(securityPolicy, channel->channelContext, &dataToEncrypt); + if(retval != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(connection, &buf); + return retval; + } + } + + /* Send the message, the buffer is freed in the network layer */ + buf.length = respHeader.messageHeader.messageSize; + retval = connection->send(connection, &buf); +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + retval |= sendAsym_sendFailure +#endif + return retval; +} + +/**************************/ +/* Send Symmetric Message */ +/**************************/ + +static UA_UInt16 +calculatePaddingSym(const UA_SecurityPolicy *securityPolicy, const void *channelContext, + size_t bytesToWrite, UA_Byte *paddingSize, UA_Byte *extraPaddingSize) { + + size_t encryptionBlockSize = securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. + getLocalBlockSize(securityPolicy, channelContext); + size_t signatureSize = securityPolicy->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, channelContext); + + UA_UInt16 padding = (UA_UInt16)(encryptionBlockSize - ((bytesToWrite + signatureSize + 1) % encryptionBlockSize)); + *paddingSize = (UA_Byte)padding; + *extraPaddingSize = (UA_Byte)(padding >> 8); + return padding; +} + +static void +setBufPos(UA_MessageContext *mc) { + const UA_SecureChannel *channel = mc->channel; + const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; + + /* 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]; + mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length]; + + /* 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 -= securityPolicy->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, 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 = securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. + getLocalBlockSize(securityPolicy, channel->channelContext ); + mc->buf_end -= 1 + ((encryptionBlockSize >> 8) ? 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; + } +} + +static UA_StatusCode +sendSymmetricChunk(UA_MessageContext *mc) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_SecureChannel *const channel = mc->channel; + const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; + UA_Connection *const connection = channel->connection; + if(!connection) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Will this chunk surpass the capacity of the SecureChannel for the message? */ + UA_Byte *buf_body_start = mc->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH; + const UA_Byte *buf_body_end = mc->buf_pos; + size_t bodyLength = (uintptr_t)buf_body_end - (uintptr_t)buf_body_start; + mc->messageSizeSoFar += bodyLength; + mc->chunksSoFar++; + if(mc->messageSizeSoFar > connection->remoteConf.maxMessageSize && + connection->remoteConf.maxMessageSize != 0) + res = UA_STATUSCODE_BADRESPONSETOOLARGE; + if(mc->chunksSoFar > connection->remoteConf.maxChunkCount && + connection->remoteConf.maxChunkCount != 0) + res = UA_STATUSCODE_BADRESPONSETOOLARGE; + if(res != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(channel->connection, &mc->messageBuffer); + return res; + } + + /* Pad the message. The bytes for the padding and signature were removed + * from buf_end before encoding the payload. So we don't check here. */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + size_t bytesToWrite = bodyLength + UA_SEQUENCE_HEADER_LENGTH; + UA_Byte paddingSize = 0; + UA_Byte extraPaddingSize = 0; + UA_UInt16 totalPaddingSize = + calculatePaddingSym(securityPolicy, channel->channelContext, + bytesToWrite, &paddingSize, &extraPaddingSize); + + // This is <= because the paddingSize byte also has to be written. + for(UA_UInt16 i = 0; i <= totalPaddingSize; ++i) { + *mc->buf_pos = paddingSize; + ++(mc->buf_pos); + } + if(extraPaddingSize > 0) { + *mc->buf_pos = extraPaddingSize; + ++(mc->buf_pos); + } + } + + /* The total message length */ + size_t pre_sig_length = (uintptr_t)(mc->buf_pos) - (uintptr_t)mc->messageBuffer.data; + size_t 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); + /* Space for the padding and the signature have been reserved in setBufPos() */ + UA_assert(total_length <= connection->localConf.sendBufferSize); + mc->messageBuffer.length = total_length; /* For giving the buffer to the network layer */ + + /* Encode the chunk headers at the beginning of the buffer */ + UA_assert(res == UA_STATUSCODE_GOOD); + UA_Byte *header_pos = mc->messageBuffer.data; + UA_SecureConversationMessageHeader respHeader; + respHeader.secureChannelId = channel->securityToken.channelId; + respHeader.messageHeader.messageTypeAndChunkType = mc->messageType; + respHeader.messageHeader.messageSize = (UA_UInt32)total_length; + if(mc->final) + respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL; + else + respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE; + res = UA_encodeBinary(&respHeader, &UA_TRANSPORT[UA_TRANSPORT_SECURECONVERSATIONMESSAGEHEADER], + &header_pos, &mc->buf_end, NULL, NULL); + + UA_SymmetricAlgorithmSecurityHeader symSecHeader; + symSecHeader.tokenId = channel->securityToken.tokenId; + res |= UA_encodeBinary(&symSecHeader.tokenId, + &UA_TRANSPORT[UA_TRANSPORT_SYMMETRICALGORITHMSECURITYHEADER], + &header_pos, &mc->buf_end, NULL, NULL); + + UA_SequenceHeader seqHeader; + seqHeader.requestId = mc->requestId; + seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1); + res |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], + &header_pos, &mc->buf_end, NULL, NULL); + + /* Sign message */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + UA_ByteString dataToSign = mc->messageBuffer; + dataToSign.length = pre_sig_length; + UA_ByteString signature; + signature.length = securityPolicy->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(securityPolicy, channel->channelContext); + signature.data = mc->buf_pos; + res |= securityPolicy->symmetricModule.cryptoModule.signatureAlgorithm. + sign(securityPolicy, channel->channelContext, &dataToSign, &signature); + } + + /* Encrypt message */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + UA_ByteString dataToEncrypt; + dataToEncrypt.data = mc->messageBuffer.data + UA_SECUREMH_AND_SYMALGH_LENGTH; + dataToEncrypt.length = total_length - UA_SECUREMH_AND_SYMALGH_LENGTH; + res |= securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(securityPolicy, channel->channelContext, &dataToEncrypt); + } + + if(res != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(channel->connection, &mc->messageBuffer); + return res; + } + + /* Send the chunk, the buffer is freed in the network layer */ + return connection->send(channel->connection, &mc->messageBuffer); +} + +/* 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) { + /* 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; + + /* Set a new buffer for the next chunk */ + UA_Connection *connection = mc->channel->connection; + retval = connection->getSendBuffer(connection, connection->localConf.sendBufferSize, + &mc->messageBuffer); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Hide bytes for header, padding and signature */ + setBufPos(mc); + *buf_pos = mc->buf_pos; + *buf_end = mc->buf_end; + return UA_STATUSCODE_GOOD; +} + +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; + + if(messageType != UA_MESSAGETYPE_MSG && messageType != UA_MESSAGETYPE_CLO) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Create the chunking info structure */ + mc->channel = channel; + mc->requestId = requestId; + mc->chunksSoFar = 0; + mc->messageSizeSoFar = 0; + mc->final = false; + mc->messageBuffer = UA_BYTESTRING_NULL; + mc->messageType = messageType; + + /* Minimum required size */ + if(connection->localConf.sendBufferSize <= UA_SECURE_MESSAGE_HEADER_LENGTH) + return UA_STATUSCODE_BADRESPONSETOOLARGE; + + /* Allocate the message buffer */ + UA_StatusCode retval = + connection->getSendBuffer(connection, connection->localConf.sendBufferSize, + &mc->messageBuffer); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Hide bytes for header, padding and signature */ + setBufPos(mc); + return UA_STATUSCODE_GOOD; +} + +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) { + /* TODO: Send the abort message */ + if(mc->messageBuffer.length > 0) { + UA_Connection *connection = mc->channel->connection; + connection->releaseSendBuffer(connection, &mc->messageBuffer); + } + } + return retval; +} + +UA_StatusCode +UA_MessageContext_finish(UA_MessageContext *mc) { + mc->final = true; + return sendSymmetricChunk(mc); +} + +void +UA_MessageContext_abort(UA_MessageContext *mc) { + UA_Connection *connection = mc->channel->connection; + connection->releaseSendBuffer(connection, &mc->messageBuffer); +} + +UA_StatusCode +UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId, + UA_MessageType messageType, void *payload, + const UA_DataType *payloadType) { + if(!channel || !payload || !payloadType) + return UA_STATUSCODE_BADINTERNALERROR; + + if(channel->connection) { + if(channel->connection->state == UA_CONNECTION_CLOSED) + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + + UA_MessageContext mc; + UA_StatusCode retval = UA_MessageContext_begin(&mc, channel, requestId, messageType); + if(retval != UA_STATUSCODE_GOOD) + 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_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; + + retval = UA_MessageContext_encode(&mc, payload, payloadType); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + return UA_MessageContext_finish(&mc); +} + +/*****************************/ +/* Assemble Complete Message */ +/*****************************/ + +static void +UA_SecureChannel_removeChunks(UA_SecureChannel *channel, UA_UInt32 requestId) { + struct MessageEntry *me; + LIST_FOREACH(me, &channel->chunks, pointers) { + if(me->requestId == requestId) { + struct ChunkPayload *cp, *temp_cp; + SIMPLEQ_FOREACH_SAFE(cp, &me->chunkPayload, pointers, temp_cp) { + UA_ByteString_deleteMembers(&cp->bytes); + UA_free(cp); + } + LIST_REMOVE(me, pointers); + UA_free(me); + return; + } + } +} + +static UA_StatusCode +appendChunk(struct MessageEntry *messageEntry, const UA_ByteString *chunkBody) { + + struct ChunkPayload* cp = (struct ChunkPayload*)UA_malloc(sizeof(struct ChunkPayload)); + UA_StatusCode retval = UA_ByteString_copy(chunkBody, &cp->bytes); + if (retval != UA_STATUSCODE_GOOD) + return retval; + + SIMPLEQ_INSERT_TAIL(&messageEntry->chunkPayload, cp, pointers); + messageEntry->chunkPayloadSize += chunkBody->length; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_SecureChannel_appendChunk(UA_SecureChannel *channel, UA_UInt32 requestId, + const UA_ByteString *chunkBody) { + struct MessageEntry *me; + LIST_FOREACH(me, &channel->chunks, pointers) { + if(me->requestId == requestId) + break; + } + + /* No chunkentry on the channel, create one */ + if(!me) { + me = (struct MessageEntry *)UA_malloc(sizeof(struct MessageEntry)); + if(!me) + return UA_STATUSCODE_BADOUTOFMEMORY; + memset(me, 0, sizeof(struct MessageEntry)); + me->requestId = requestId; + SIMPLEQ_INIT(&me->chunkPayload); + LIST_INSERT_HEAD(&channel->chunks, me, pointers); + } + + return appendChunk(me, chunkBody); +} + +static UA_StatusCode +UA_SecureChannel_finalizeChunk(UA_SecureChannel *channel, UA_UInt32 requestId, + const UA_ByteString *chunkBody, UA_MessageType messageType, + UA_ProcessMessageCallback callback, void *application) { + struct MessageEntry *messageEntry; + LIST_FOREACH(messageEntry, &channel->chunks, pointers) { + if(messageEntry->requestId == requestId) + break; + } + + UA_ByteString bytes; + if(!messageEntry) { + bytes = *chunkBody; + } else { + UA_StatusCode retval = appendChunk(messageEntry, chunkBody); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + UA_ByteString_init(&bytes); + + bytes.data = (UA_Byte*) UA_malloc(messageEntry->chunkPayloadSize); + if (!bytes.data) + return UA_STATUSCODE_BADOUTOFMEMORY; + + struct ChunkPayload *cp, *temp_cp; + size_t curPos = 0; + SIMPLEQ_FOREACH_SAFE(cp, &messageEntry->chunkPayload, pointers, temp_cp) { + memcpy(&bytes.data[curPos], cp->bytes.data, cp->bytes.length); + curPos += cp->bytes.length; + UA_ByteString_deleteMembers(&cp->bytes); + UA_free(cp); + } + + bytes.length = messageEntry->chunkPayloadSize; + + LIST_REMOVE(messageEntry, pointers); + UA_free(messageEntry); + } + + UA_StatusCode retval = callback(application, channel, messageType, requestId, &bytes); + if(messageEntry) + UA_ByteString_deleteMembers(&bytes); + return retval; +} + +/****************************/ +/* Process a received Chunk */ +/****************************/ + +static UA_StatusCode +decryptChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cryptoModule, + UA_ByteString *chunk, size_t offset, UA_UInt32 *requestId, UA_UInt32 *sequenceNumber, + UA_ByteString *payload, UA_MessageType messageType) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; + size_t chunkSizeAfterDecryption = chunk->length; + + /* Decrypt the chunk. Always decrypt opn messages if mode not none */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || + messageType == UA_MESSAGETYPE_OPN) { + UA_ByteString cipherText = {chunk->length - offset, chunk->data + offset}; + size_t sizeBeforeDecryption = cipherText.length; + retval = cryptoModule->encryptionAlgorithm.decrypt(securityPolicy, channel->channelContext, &cipherText); + chunkSizeAfterDecryption -= (sizeBeforeDecryption - cipherText.length); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Verify the chunk signature */ + size_t sigsize = 0; + size_t paddingSize = 0; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || + messageType == UA_MESSAGETYPE_OPN) { + /* Compute the padding size */ + sigsize = cryptoModule->signatureAlgorithm.getRemoteSignatureSize(securityPolicy, channel->channelContext); + + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || + (messageType == UA_MESSAGETYPE_OPN && + channel->securityMode > UA_MESSAGESECURITYMODE_NONE)) { + paddingSize = (size_t)chunk->data[chunkSizeAfterDecryption - sigsize - 1]; + + size_t keyLength = + cryptoModule->encryptionAlgorithm.getRemoteKeyLength(securityPolicy, channel->channelContext); + if(keyLength > 2048) { + paddingSize <<= 8; /* Extra padding size */ + paddingSize += chunk->data[chunkSizeAfterDecryption - sigsize - 2]; + // see comment below but for extraPaddingSize + paddingSize += 1; + } + + // we need to add one to the padding size since the paddingSize byte itself need to be removed as well. + // TODO: write unit test for correct padding calculation + paddingSize += 1; + } + if(offset + paddingSize + sigsize >= chunkSizeAfterDecryption) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + + /* Verify the signature */ + const UA_ByteString chunkDataToVerify = {chunkSizeAfterDecryption - sigsize, chunk->data}; + const UA_ByteString signature = {sigsize, chunk->data + chunkSizeAfterDecryption - sigsize}; + retval = cryptoModule->signatureAlgorithm.verify(securityPolicy, channel->channelContext, + &chunkDataToVerify, &signature); +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + retval |= decrypt_verifySignatureFailure; +#endif + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Decode the sequence header */ + UA_SequenceHeader sequenceHeader; + retval = UA_SequenceHeader_decodeBinary(chunk, &offset, &sequenceHeader); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + if(offset + paddingSize + sigsize >= chunk->length) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + + *requestId = sequenceHeader.requestId; + *sequenceNumber = sequenceHeader.sequenceNumber; + payload->data = chunk->data + offset; + payload->length = chunkSizeAfterDecryption - offset - sigsize - paddingSize; + return UA_STATUSCODE_GOOD; +} + +typedef UA_StatusCode(*UA_SequenceNumberCallback)(UA_SecureChannel *channel, + UA_UInt32 sequenceNumber); + +static UA_StatusCode +processSequenceNumberAsym(UA_SecureChannel *const channel, UA_UInt32 sequenceNumber) { + channel->receiveSequenceNumber = sequenceNumber; + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +processSequenceNumberSym(UA_SecureChannel *const channel, UA_UInt32 sequenceNumber) { + /* Failure mode hook for unit tests */ +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + 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 + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + ++channel->receiveSequenceNumber; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +checkAsymHeader(UA_SecureChannel *const channel, + UA_AsymmetricAlgorithmSecurityHeader *const asymHeader) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + const UA_SecurityPolicy *const securityPolicy = channel->securityPolicy; + + if(!UA_ByteString_equal(&securityPolicy->policyUri, &asymHeader->securityPolicyUri)) { + return UA_STATUSCODE_BADSECURITYPOLICYREJECTED; + } + + // TODO: Verify certificate using certificate plugin. This will come with a new PR + /* Something like this + retval = certificateManager->verify(certificateStore??, &asymHeader->senderCertificate); + if(retval != UA_STATUSCODE_GOOD) + return retval; + */ + retval = securityPolicy->asymmetricModule. + compareCertificateThumbprint(securityPolicy, &asymHeader->receiverCertificateThumbprint); + if(retval != UA_STATUSCODE_GOOD) { + return retval; + } + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +checkPreviousToken(UA_SecureChannel *const channel, const UA_UInt32 tokenId) { + if(tokenId != channel->previousSecurityToken.tokenId) + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; + + UA_DateTime timeout = channel->previousSecurityToken.createdAt + + (UA_DateTime)((UA_Double)channel->previousSecurityToken.revisedLifetime * + (UA_Double)UA_DATETIME_MSEC * + 1.25); + + if(timeout < UA_DateTime_nowMonotonic()) { + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; + } + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +checkSymHeader(UA_SecureChannel *const channel, + const UA_UInt32 tokenId, UA_Boolean allowPreviousToken) { + + if(tokenId == channel->securityToken.tokenId) { + if(channel->state == UA_SECURECHANNELSTATE_OPEN && + (channel->securityToken.createdAt + + (channel->securityToken.revisedLifetime * UA_DATETIME_MSEC)) < UA_DateTime_nowMonotonic()) { + UA_SecureChannel_deleteMembersCleanup(channel); + return UA_STATUSCODE_BADSECURECHANNELCLOSED; + } + } + + if(tokenId != channel->securityToken.tokenId) { + if(tokenId != channel->nextSecurityToken.tokenId) { + if(allowPreviousToken) + return checkPreviousToken(channel, tokenId); + else + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN; + } + return UA_SecureChannel_revolveTokens(channel); + } + + if(channel->previousSecurityToken.tokenId != 0) { + UA_StatusCode retval = UA_SecureChannel_generateRemoteKeys(channel, channel->securityPolicy); + UA_ChannelSecurityToken_deleteMembers(&channel->previousSecurityToken); + return retval; + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_SecureChannel_processChunk(UA_SecureChannel *channel, UA_ByteString *chunk, + UA_ProcessMessageCallback callback, + void *application, UA_Boolean allowPreviousToken) { + /* Decode message header */ + size_t offset = 0; + UA_SecureConversationMessageHeader messageHeader; + UA_StatusCode retval = + UA_SecureConversationMessageHeader_decodeBinary(chunk, &offset, &messageHeader); + if(retval != UA_STATUSCODE_GOOD) + return retval; + +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + /* The wrong ChannelId. Non-opened channels have the id zero. */ + if(messageHeader.secureChannelId != channel->securityToken.channelId && + channel->state != UA_SECURECHANNELSTATE_FRESH) + return UA_STATUSCODE_BADSECURECHANNELIDINVALID; +#endif + + UA_MessageType messageType = (UA_MessageType) + (messageHeader.messageHeader.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE); + UA_ChunkType chunkType = (UA_ChunkType) + (messageHeader.messageHeader.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE); + + /* ERR message (not encrypted) */ + UA_UInt32 requestId = 0; + UA_UInt32 sequenceNumber = 0; + UA_ByteString chunkPayload; + const UA_SecurityPolicyCryptoModule *cryptoModule = NULL; + UA_SequenceNumberCallback sequenceNumberCallback = NULL; + + switch(messageType) { + case UA_MESSAGETYPE_ERR: { + if(chunkType != UA_CHUNKTYPE_FINAL) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + chunkPayload.length = chunk->length - offset; + chunkPayload.data = chunk->data + offset; + return callback(application, channel, messageType, requestId, &chunkPayload); + } + + case UA_MESSAGETYPE_MSG: + case UA_MESSAGETYPE_CLO: { + /* Decode and check the symmetric security header (tokenId) */ + UA_SymmetricAlgorithmSecurityHeader symmetricSecurityHeader; + UA_SymmetricAlgorithmSecurityHeader_init(&symmetricSecurityHeader); + retval = UA_SymmetricAlgorithmSecurityHeader_decodeBinary(chunk, &offset, + &symmetricSecurityHeader); + if(retval != UA_STATUSCODE_GOOD) + return retval; + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Help fuzzing by always setting the correct tokenId */ + symmetricSecurityHeader.tokenId = channel->securityToken.tokenId; +#endif + + retval = checkSymHeader(channel, symmetricSecurityHeader.tokenId, allowPreviousToken); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + cryptoModule = &channel->securityPolicy->symmetricModule.cryptoModule; + sequenceNumberCallback = processSequenceNumberSym; + break; + } + case UA_MESSAGETYPE_OPN: { + /* Chunking not allowed for OPN */ + if(chunkType != UA_CHUNKTYPE_FINAL) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + + /* Decode the asymmetric algorithm security header and call the callback + * to perform checks. */ + UA_AsymmetricAlgorithmSecurityHeader asymHeader; + UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); + offset = UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH; + retval = UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(chunk, &offset, &asymHeader); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + retval = checkAsymHeader(channel, &asymHeader); + UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + cryptoModule = &channel->securityPolicy->asymmetricModule.cryptoModule; + sequenceNumberCallback = processSequenceNumberAsym; + break; + } + default:return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + + /* Decrypt message */ + UA_assert(cryptoModule != NULL); + retval = decryptChunk(channel, cryptoModule, chunk, offset, &requestId, + &sequenceNumber, &chunkPayload, messageType); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Check the sequence number */ + if(sequenceNumberCallback == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + retval = sequenceNumberCallback(channel, sequenceNumber); + + /* Skip sequence number checking for fuzzer to improve coverage */ + if(retval != UA_STATUSCODE_GOOD) { +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + return retval; +#else + retval = UA_STATUSCODE_GOOD; +#endif + } + + /* Process the payload */ + if(chunkType == UA_CHUNKTYPE_FINAL) { + retval = UA_SecureChannel_finalizeChunk(channel, requestId, &chunkPayload, + messageType, callback, application); + } else if(chunkType == UA_CHUNKTYPE_INTERMEDIATE) { + retval = UA_SecureChannel_appendChunk(channel, requestId, &chunkPayload); + } else if(chunkType == UA_CHUNKTYPE_ABORT) { + UA_SecureChannel_removeChunks(channel, requestId); + } else { + retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + return retval; +} + +/* 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/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA + */ + +#ifdef UA_ENABLE_SUBSCRIPTIONS +#endif + +#define UA_SESSION_NONCELENTH 32 + +void UA_Session_init(UA_Session *session) { + memset(session, 0, sizeof(UA_Session)); + session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS; +#ifdef UA_ENABLE_SUBSCRIPTIONS + SIMPLEQ_INIT(&session->responseQueue); +#endif +} + +#ifdef UA_ENABLE_SUBSCRIPTIONS +static void +deleteSubscription(UA_Server *server, UA_Session *session, + UA_Subscription *sub) { + UA_Subscription_deleteMembers(server, sub); + + /* Add a delayed callback to remove the subscription when the currently + * scheduled jobs have completed */ + UA_StatusCode retval = UA_Server_delayedFree(server, sub); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(server->config.logger, session, + "Could not remove subscription with error code %s", + UA_StatusCode_name(retval)); + } + + /* Remove from the session */ + LIST_REMOVE(sub, listEntry); + UA_assert(session->numSubscriptions > 0); + session->numSubscriptions--; +} +#endif + +void UA_Session_deleteMembersCleanup(UA_Session *session, UA_Server *server) { + 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); + struct ContinuationPointEntry *cp, *temp; + LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) { + LIST_REMOVE(cp, pointers); + UA_ByteString_deleteMembers(&cp->identifier); + UA_BrowseDescription_deleteMembers(&cp->browseDescription); + UA_free(cp); + } + +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_Subscription *sub, *sub_tmp; + LIST_FOREACH_SAFE(sub, &session->serverSubscriptions, listEntry, sub_tmp) { + deleteSubscription(server, session, sub); + } +#endif +} + +void UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel) { + LIST_INSERT_HEAD(&channel->sessions, &session->header, pointers); + session->header.channel = channel; +} + +void UA_Session_detachFromSecureChannel(UA_Session *session) { + if(!session->header.channel) + return; + session->header.channel = NULL; + LIST_REMOVE(&session->header, pointers); +} + +UA_StatusCode +UA_Session_generateNonce(UA_Session *session) { + UA_SecureChannel *channel = session->header.channel; + if(!channel || !channel->securityPolicy) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Is the length of the previous nonce correct? */ + if(session->serverNonce.length != UA_SESSION_NONCELENTH) { + UA_ByteString_deleteMembers(&session->serverNonce); + UA_StatusCode retval = + UA_ByteString_allocBuffer(&session->serverNonce, UA_SESSION_NONCELENTH); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + return channel->securityPolicy->symmetricModule. + generateNonce(channel->securityPolicy, &session->serverNonce); +} + +void UA_Session_updateLifetime(UA_Session *session) { + session->validTill = UA_DateTime_nowMonotonic() + + (UA_DateTime)(session->timeout * UA_DATETIME_MSEC); +} + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +void UA_Session_addSubscription(UA_Session *session, UA_Subscription *newSubscription) { + newSubscription->subscriptionId = ++session->lastSubscriptionId; + + LIST_INSERT_HEAD(&session->serverSubscriptions, newSubscription, listEntry); + session->numSubscriptions++; +} + +UA_StatusCode +UA_Session_deleteSubscription(UA_Server *server, UA_Session *session, + UA_UInt32 subscriptionId) { + UA_Subscription *sub = UA_Session_getSubscriptionById(session, subscriptionId); + if(!sub) + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + + deleteSubscription(server, session, sub); + return UA_STATUSCODE_GOOD; +} + +UA_Subscription * +UA_Session_getSubscriptionById(UA_Session *session, UA_UInt32 subscriptionId) { + UA_Subscription *sub; + LIST_FOREACH(sub, &session->serverSubscriptions, listEntry) { + if(sub->subscriptionId == subscriptionId) + break; + } + return sub; +} + +UA_PublishResponseEntry* +UA_Session_dequeuePublishReq(UA_Session *session) { + UA_PublishResponseEntry* entry = SIMPLEQ_FIRST(&session->responseQueue); + if(entry) { + SIMPLEQ_REMOVE_HEAD(&session->responseQueue, listEntry); + session->numPublishReq--; + } + return entry; +} + +void +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++; +} + +#endif + +/*********************************** amalgamated original file "/home/jvoe/open62541/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-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015, 2017 (c) Florian Palm + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Julian Grothoff + */ + + +/* There is no UA_Node_new() method here. Creating nodes is part of the + * NodeStore layer */ + +void UA_Node_deleteMembers(UA_Node *node) { + /* Delete standard content */ + UA_NodeId_deleteMembers(&node->nodeId); + UA_QualifiedName_deleteMembers(&node->browseName); + UA_LocalizedText_deleteMembers(&node->displayName); + UA_LocalizedText_deleteMembers(&node->description); + + /* Delete references */ + UA_Node_deleteReferences(node); + + /* Delete unique content of the nodeclass */ + switch(node->nodeClass) { + case UA_NODECLASS_OBJECT: + break; + case UA_NODECLASS_METHOD: + break; + case UA_NODECLASS_OBJECTTYPE: + break; + case UA_NODECLASS_VARIABLE: + case UA_NODECLASS_VARIABLETYPE: { + UA_VariableNode *p = (UA_VariableNode*)node; + UA_NodeId_deleteMembers(&p->dataType); + UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_INT32]); + p->arrayDimensions = NULL; + p->arrayDimensionsSize = 0; + if(p->valueSource == UA_VALUESOURCE_DATA) + UA_DataValue_deleteMembers(&p->value.data.value); + break; + } + case UA_NODECLASS_REFERENCETYPE: { + UA_ReferenceTypeNode *p = (UA_ReferenceTypeNode*)node; + UA_LocalizedText_deleteMembers(&p->inverseName); + break; + } + case UA_NODECLASS_DATATYPE: + break; + case UA_NODECLASS_VIEW: + break; + default: + break; + } +} + +static UA_StatusCode +UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) { + dst->eventNotifier = src->eventNotifier; + return UA_STATUSCODE_GOOD; +} + +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]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + dst->arrayDimensionsSize = src->arrayDimensionsSize; + retval = UA_NodeId_copy(&src->dataType, &dst->dataType); + dst->valueRank = src->valueRank; + dst->valueSource = src->valueSource; + if(src->valueSource == UA_VALUESOURCE_DATA) { + retval |= UA_DataValue_copy(&src->value.data.value, + &dst->value.data.value); + dst->value.data.callback = src->value.data.callback; + } else + dst->value.dataSource = src->value.dataSource; + return retval; +} + +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; +} + +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; +} + +static UA_StatusCode +UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) { + dst->executable = src->executable; + dst->method = src->method; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) { + dst->isAbstract = src->isAbstract; + dst->lifecycle = src->lifecycle; + return UA_STATUSCODE_GOOD; +} + +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; +} + +static UA_StatusCode +UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) { + dst->isAbstract = src->isAbstract; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) { + dst->containsNoLoops = src->containsNoLoops; + dst->eventNotifier = src->eventNotifier; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Node_copy(const UA_Node *src, UA_Node *dst) { + if(src->nodeClass != dst->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; + if(retval != UA_STATUSCODE_GOOD) { + UA_Node_deleteMembers(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) { + UA_Node_deleteMembers(dst); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + dst->referencesSize = src->referencesSize; + + for(size_t i = 0; i < src->referencesSize; ++i) { + UA_NodeReferenceKind *srefs = &src->references[i]; + UA_NodeReferenceKind *drefs = &dst->references[i]; + drefs->isInverse = srefs->isInverse; + retval = UA_NodeId_copy(&srefs->referenceTypeId, &drefs->referenceTypeId); + if(retval != UA_STATUSCODE_GOOD) + break; + retval = UA_Array_copy(srefs->targetIds, srefs->targetIdsSize, + (void**)&drefs->targetIds, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + if(retval != UA_STATUSCODE_GOOD) + break; + drefs->targetIdsSize = srefs->targetIdsSize; + } + if(retval != UA_STATUSCODE_GOOD) { + UA_Node_deleteMembers(dst); + return retval; + } + } + + /* Copy unique content of the nodeclass */ + switch(src->nodeClass) { + case UA_NODECLASS_OBJECT: + retval = UA_ObjectNode_copy((const UA_ObjectNode*)src, (UA_ObjectNode*)dst); + break; + case UA_NODECLASS_VARIABLE: + retval = UA_VariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst); + break; + case UA_NODECLASS_METHOD: + retval = UA_MethodNode_copy((const UA_MethodNode*)src, (UA_MethodNode*)dst); + break; + case UA_NODECLASS_OBJECTTYPE: + retval = UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)src, (UA_ObjectTypeNode*)dst); + break; + case UA_NODECLASS_VARIABLETYPE: + retval = UA_VariableTypeNode_copy((const UA_VariableTypeNode*)src, (UA_VariableTypeNode*)dst); + break; + case UA_NODECLASS_REFERENCETYPE: + retval = UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)src, (UA_ReferenceTypeNode*)dst); + break; + case UA_NODECLASS_DATATYPE: + retval = UA_DataTypeNode_copy((const UA_DataTypeNode*)src, (UA_DataTypeNode*)dst); + break; + case UA_NODECLASS_VIEW: + retval = UA_ViewNode_copy((const UA_ViewNode*)src, (UA_ViewNode*)dst); + break; + default: + break; + } + + if(retval != UA_STATUSCODE_GOOD) + UA_Node_deleteMembers(dst); + + return retval; +} + +UA_Node * +UA_Node_copy_alloc(const UA_Node *src) { + // use dstPtr to trick static code analysis in accepting dirty cast + void *dstPtr; + switch(src->nodeClass) { + case UA_NODECLASS_OBJECT: + dstPtr = UA_malloc(sizeof(UA_ObjectNode)); + break; + case UA_NODECLASS_VARIABLE: + dstPtr =UA_malloc(sizeof(UA_VariableNode)); + break; + case UA_NODECLASS_METHOD: + dstPtr = UA_malloc(sizeof(UA_MethodNode)); + break; + case UA_NODECLASS_OBJECTTYPE: + dstPtr = UA_malloc(sizeof(UA_ObjectTypeNode)); + break; + case UA_NODECLASS_VARIABLETYPE: + dstPtr = UA_malloc(sizeof(UA_VariableTypeNode)); + break; + case UA_NODECLASS_REFERENCETYPE: + dstPtr = UA_malloc(sizeof(UA_ReferenceTypeNode)); + break; + case UA_NODECLASS_DATATYPE: + dstPtr = UA_malloc(sizeof(UA_DataTypeNode)); + break; + case UA_NODECLASS_VIEW: + dstPtr = UA_malloc(sizeof(UA_ViewNode)); + break; + default: + return NULL; + } + UA_Node *dst = (UA_Node*)dstPtr; + dst->nodeClass = src->nodeClass; + + UA_StatusCode retval = UA_Node_copy(src, dst); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(dst); + return NULL; + } + return dst; +} +/******************************/ +/* Copy Attributes into Nodes */ +/******************************/ + +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 = UA_LocalizedText_copy(&attr->displayName, + &node->displayName); + retval |= UA_LocalizedText_copy(&attr->description, &node->description); + node->writeMask = attr->writeMask; + return retval; +} + +static UA_StatusCode +copyCommonVariableAttributes(UA_VariableNode *node, + const UA_VariableAttributes *attr) { + /* Copy the array dimensions */ + UA_StatusCode retval = + UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize, + (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + node->arrayDimensionsSize = attr->arrayDimensionsSize; + + /* Data type and value rank */ + retval |= UA_NodeId_copy(&attr->dataType, &node->dataType); + node->valueRank = attr->valueRank; + + /* Copy the value */ + node->valueSource = UA_VALUESOURCE_DATA; + UA_NodeId extensionObject = UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE); + /* if we have an extension object which is still encoded (e.g. from the nodeset compiler) + * we need to decode it and set the decoded value instead of the encoded object */ + UA_Boolean valueSet = false; + if(attr->value.type != NULL && UA_NodeId_equal(&attr->value.type->typeId, &extensionObject)) { + + if (attr->value.data == UA_EMPTY_ARRAY_SENTINEL) { + /* do nothing since we got an empty array of extension objects */ + return UA_STATUSCODE_GOOD; + } + + const UA_ExtensionObject *obj = (const UA_ExtensionObject *)attr->value.data; + if(obj && obj->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) { + + /* TODO: Once we generate type description in the nodeset compiler, + * UA_findDatatypeByBinary can be made internal to the decoding + * layer. */ + const UA_DataType *type = UA_findDataTypeByBinary(&obj->content.encoded.typeId); + + if(type) { + void *dst = UA_Array_new(attr->value.arrayLength, type); + if (!dst) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + uint8_t *tmpPos = (uint8_t *)dst; + + for(size_t i=0; i<attr->value.arrayLength; i++) { + size_t offset =0; + const UA_ExtensionObject *curr = &((const UA_ExtensionObject *)attr->value.data)[i]; + UA_StatusCode ret = UA_decodeBinary(&curr->content.encoded.body, &offset, tmpPos, type, 0, NULL); + if(ret != UA_STATUSCODE_GOOD) { + return ret; + } + tmpPos += type->memSize; + } + + UA_Variant_setArray(&node->value.data.value.value, dst, attr->value.arrayLength, type); + valueSet = true; + } + } + } + + if(!valueSet) + retval |= UA_Variant_copy(&attr->value, &node->value.data.value.value); + + node->value.data.value.hasValue = true; + + return retval; +} + +static UA_StatusCode +copyVariableNodeAttributes(UA_VariableNode *vnode, + const UA_VariableAttributes *attr) { + vnode->accessLevel = attr->accessLevel; + vnode->historizing = attr->historizing; + vnode->minimumSamplingInterval = attr->minimumSamplingInterval; + return copyCommonVariableAttributes(vnode, attr); +} + +static UA_StatusCode +copyVariableTypeNodeAttributes(UA_VariableTypeNode *vtnode, + const UA_VariableTypeAttributes *attr) { + vtnode->isAbstract = attr->isAbstract; + return copyCommonVariableAttributes((UA_VariableNode*)vtnode, + (const UA_VariableAttributes*)attr); +} + +static UA_StatusCode +copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) { + onode->eventNotifier = attr->eventNotifier; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode, + const UA_ReferenceTypeAttributes *attr) { + rtnode->isAbstract = attr->isAbstract; + rtnode->symmetric = attr->symmetric; + return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName); +} + +static UA_StatusCode +copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode, + const UA_ObjectTypeAttributes *attr) { + otnode->isAbstract = attr->isAbstract; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) { + vnode->containsNoLoops = attr->containsNoLoops; + vnode->eventNotifier = attr->eventNotifier; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode, + const UA_DataTypeAttributes *attr) { + dtnode->isAbstract = attr->isAbstract; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +copyMethodNodeAttributes(UA_MethodNode *mnode, + const UA_MethodAttributes *attr) { + mnode->executable = attr->executable; + return UA_STATUSCODE_GOOD; +} + +#define CHECK_ATTRIBUTES(TYPE) \ + if(attributeType != &UA_TYPES[UA_TYPES_##TYPE]) { \ + retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; \ + break; \ + } + +UA_StatusCode +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) { + case UA_NODECLASS_OBJECT: + CHECK_ATTRIBUTES(OBJECTATTRIBUTES); + retval = copyObjectNodeAttributes((UA_ObjectNode*)node, + (const UA_ObjectAttributes*)attributes); + break; + case UA_NODECLASS_VARIABLE: + CHECK_ATTRIBUTES(VARIABLEATTRIBUTES); + retval = copyVariableNodeAttributes((UA_VariableNode*)node, + (const UA_VariableAttributes*)attributes); + break; + case UA_NODECLASS_OBJECTTYPE: + CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES); + retval = copyObjectTypeNodeAttributes((UA_ObjectTypeNode*)node, + (const UA_ObjectTypeAttributes*)attributes); + break; + case UA_NODECLASS_VARIABLETYPE: + CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES); + retval = copyVariableTypeNodeAttributes((UA_VariableTypeNode*)node, + (const UA_VariableTypeAttributes*)attributes); + break; + case UA_NODECLASS_REFERENCETYPE: + CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES); + retval = copyReferenceTypeNodeAttributes((UA_ReferenceTypeNode*)node, + (const UA_ReferenceTypeAttributes*)attributes); + break; + case UA_NODECLASS_DATATYPE: + CHECK_ATTRIBUTES(DATATYPEATTRIBUTES); + retval = copyDataTypeNodeAttributes((UA_DataTypeNode*)node, + (const UA_DataTypeAttributes*)attributes); + break; + case UA_NODECLASS_VIEW: + CHECK_ATTRIBUTES(VIEWATTRIBUTES); + retval = copyViewNodeAttributes((UA_ViewNode*)node, + (const UA_ViewAttributes*)attributes); + break; + case UA_NODECLASS_METHOD: + CHECK_ATTRIBUTES(METHODATTRIBUTES); + retval = copyMethodNodeAttributes((UA_MethodNode*)node, + (const UA_MethodAttributes*)attributes); + break; + case UA_NODECLASS_UNSPECIFIED: + default: + retval = UA_STATUSCODE_BADNODECLASSINVALID; + } + + if(retval == UA_STATUSCODE_GOOD) + retval = copyStandardAttributes(node, (const UA_NodeAttributes*)attributes); + if(retval != UA_STATUSCODE_GOOD) + UA_Node_deleteMembers(node); + return retval; +} + +/*********************/ +/* Manage References */ +/*********************/ + +static UA_StatusCode +addReferenceTarget(UA_NodeReferenceKind *refs, const UA_ExpandedNodeId *target) { + UA_ExpandedNodeId *targets = + (UA_ExpandedNodeId*) UA_realloc(refs->targetIds, + sizeof(UA_ExpandedNodeId) * (refs->targetIdsSize+1)); + if(!targets) + return UA_STATUSCODE_BADOUTOFMEMORY; + + refs->targetIds = targets; + UA_StatusCode retval = + UA_ExpandedNodeId_copy(target, &refs->targetIds[refs->targetIdsSize]); + + if(retval == UA_STATUSCODE_GOOD) { + refs->targetIdsSize++; + } else if(refs->targetIdsSize == 0) { + /* We had zero references before (realloc was a malloc) */ + UA_free(refs->targetIds); + refs->targetIds = NULL; + } + return retval; +} + +static UA_StatusCode +addReferenceKind(UA_Node *node, const UA_AddReferencesItem *item) { + UA_NodeReferenceKind *refs = + (UA_NodeReferenceKind*)UA_realloc(node->references, + sizeof(UA_NodeReferenceKind) * (node->referencesSize+1)); + if(!refs) + return UA_STATUSCODE_BADOUTOFMEMORY; + node->references = refs; + UA_NodeReferenceKind *newRef = &refs[node->referencesSize]; + memset(newRef, 0, sizeof(UA_NodeReferenceKind)); + + newRef->isInverse = !item->isForward; + UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &newRef->referenceTypeId); + retval |= addReferenceTarget(newRef, &item->targetNodeId); + + if(retval == UA_STATUSCODE_GOOD) { + node->referencesSize++; + } else { + UA_NodeId_deleteMembers(&newRef->referenceTypeId); + if(node->referencesSize == 0) { + UA_free(node->references); + node->references = NULL; + } + } + return retval; +} + +UA_StatusCode +UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item) { + 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; + } + } + if(existingRefs != NULL) { + for(size_t i = 0; i < existingRefs->targetIdsSize; i++) { + if(UA_ExpandedNodeId_equal(&existingRefs->targetIds[i], + &item->targetNodeId)) { + return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED; + } + } + return addReferenceTarget(existingRefs, &item->targetNodeId); + } + return addReferenceKind(node, item); +} + +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) + continue; + if(!UA_NodeId_equal(&item->referenceTypeId, &refs->referenceTypeId)) + continue; + + for(size_t j = refs->targetIdsSize; j > 0; --j) { + if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &refs->targetIds[j-1].nodeId)) + continue; + + /* Ok, delete the reference */ + UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j-1]); + refs->targetIdsSize--; + + /* One matching target remaining */ + if(refs->targetIdsSize > 0) { + if(j-1 != refs->targetIdsSize) // avoid valgrind error: Source + // and destination overlap in + // memcpy + refs->targetIds[j-1] = refs->targetIds[refs->targetIdsSize]; + return UA_STATUSCODE_GOOD; + } + + /* Remove refs */ + UA_free(refs->targetIds); + UA_NodeId_deleteMembers(&refs->referenceTypeId); + node->referencesSize--; + if(node->referencesSize > 0) { + if(i-1 != node->referencesSize) // avoid valgrind error: Source + // and destination overlap in + // memcpy + node->references[i-1] = node->references[node->referencesSize]; + return UA_STATUSCODE_GOOD; + } + + /* Remove the node references */ + UA_free(node->references); + node->references = NULL; + return UA_STATUSCODE_GOOD; + } + } + return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED; +} + +void UA_Node_deleteReferences(UA_Node *node) { + for(size_t i = 0; i < node->referencesSize; ++i) { + UA_NodeReferenceKind *refs = &node->references[i]; + UA_Array_delete(refs->targetIds, refs->targetIdsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_NodeId_deleteMembers(&refs->referenceTypeId); + } + if(node->references) + UA_free(node->references); + node->references = NULL; + node->referencesSize = 0; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015-2016 (c) Chris Iatrou + * Copyright 2015 (c) LEvertz + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2016 (c) Julian Grothoff + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) Lorenz Haas + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +/**********************/ +/* Namespace Handling */ +/**********************/ + +UA_UInt16 addNamespace(UA_Server *server, const UA_String name) { + /* Check if the namespace already exists in the server's namespace array */ + for(UA_UInt16 i = 0; i < server->namespacesSize; ++i) { + if(UA_String_equal(&name, &server->namespaces[i])) + return i; + } + + /* Make the array bigger */ + UA_String *newNS = (UA_String*)UA_realloc(server->namespaces, + sizeof(UA_String) * (server->namespacesSize + 1)); + if(!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; + + /* Announce the change (otherwise, the array appears unchanged) */ + ++server->namespacesSize; + return (UA_UInt16)(server->namespacesSize - 1); +} + +UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) { + /* Override const attribute to get string (dirty hack) */ + UA_String nameString; + nameString.length = strlen(name); + nameString.data = (UA_Byte*)(uintptr_t)name; + return addNamespace(server, nameString); +} + +UA_StatusCode +UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle) { + const UA_Node *parent = + server->config.nodestore.getNode(server->config.nodestore.context, + &parentNodeId); + if(!parent) + return UA_STATUSCODE_BADNODEIDINVALID; + + /* 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) { + server->config.nodestore.releaseNode(server->config.nodestore.context, parent); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + 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->targetIdsSize; j++) + retval |= callback(ref->targetIds[j].nodeId, ref->isInverse, + ref->referenceTypeId, handle); + } + UA_Node_deleteMembers(parentCopy); + UA_free(parentCopy); + + server->config.nodestore.releaseNode(server->config.nodestore.context, parent); + return retval; +} + +/********************/ +/* Server Lifecycle */ +/********************/ + +/* The server needs to be stopped before it can be deleted */ +void UA_Server_delete(UA_Server *server) { + /* Delete all internal data */ + UA_SecureChannelManager_deleteMembers(&server->secureChannelManager); + UA_SessionManager_deleteMembers(&server->sessionManager); + UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]); + +#ifdef UA_ENABLE_DISCOVERY + registeredServer_list_entry *rs, *rs_tmp; + LIST_FOREACH_SAFE(rs, &server->registeredServers, pointers, rs_tmp) { + LIST_REMOVE(rs, pointers); + UA_RegisteredServer_deleteMembers(&rs->registeredServer); + UA_free(rs); + } + periodicServerRegisterCallback_entry *ps, *ps_tmp; + LIST_FOREACH_SAFE(ps, &server->periodicServerRegisterCallbacks, pointers, ps_tmp) { + LIST_REMOVE(ps, pointers); + UA_free(ps->callback); + UA_free(ps); + } + +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) + destroyMulticastDiscoveryServer(server); + + serverOnNetwork_list_entry *son, *son_tmp; + LIST_FOREACH_SAFE(son, &server->serverOnNetwork, pointers, son_tmp) { + LIST_REMOVE(son, pointers); + UA_ServerOnNetwork_deleteMembers(&son->serverOnNetwork); + if(son->pathTmp) + UA_free(son->pathTmp); + UA_free(son); + } + + for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_PRIME; i++) { + serverOnNetwork_hash_entry* currHash = server->serverOnNetworkHash[i]; + while(currHash) { + serverOnNetwork_hash_entry* nextHash = currHash->next; + UA_free(currHash); + currHash = nextHash; + } + } +# endif + +#endif + + /* Clean up the admin session */ + UA_Session_deleteMembersCleanup(&server->adminSession, server); + +#ifdef UA_ENABLE_MULTITHREADING + /* Process new delayed callbacks from the cleanup */ + UA_Server_cleanupDispatchQueue(server); + pthread_mutex_destroy(&server->dispatchQueue_accessMutex); + pthread_cond_destroy(&server->dispatchQueue_condition); + pthread_mutex_destroy(&server->dispatchQueue_conditionMutex); +#else + /* Process new delayed callbacks from the cleanup */ + UA_Server_cleanupDelayedCallbacks(server); +#endif + + /* Delete the timed work */ + UA_Timer_deleteMembers(&server->timer); + + /* Delete the server itself */ + UA_free(server); +} + +/* Recurring cleanup. Removing unused and timed-out channels and sessions */ +static void +UA_Server_cleanup(UA_Server *server, void *_) { + UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic(); + UA_SessionManager_cleanupTimedOut(&server->sessionManager, nowMonotonic); + UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, nowMonotonic); +#ifdef UA_ENABLE_DISCOVERY + UA_Discovery_cleanupTimedOut(server, nowMonotonic); +#endif +} + +/********************/ +/* Server Lifecycle */ +/********************/ + +UA_Server * +UA_Server_new(const UA_ServerConfig *config) { + /* A config is required */ + if(!config) + return NULL; + + /* At least one endpoint has to be configured */ + if(config->endpointsSize == 0) { + UA_LOG_FATAL(config->logger, UA_LOGCATEGORY_SERVER, + "There has to be at least one endpoint."); + return NULL; + } + + /* Allocate the server */ + UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server)); + if(!server) + return NULL; + + /* Set the config */ + server->config = *config; + + /* Initialize the admin session */ + UA_Session_init(&server->adminSession); + server->adminSession.header.authenticationToken = UA_NODEID_NUMERIC(0, 1); + server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID; + server->adminSession.sessionId.identifier.guid.data1 = 1; + server->adminSession.sessionName = UA_STRING_ALLOC("Administrator Session"); + server->adminSession.validTill = UA_INT64_MAX; + server->adminSession.availableContinuationPoints = UA_MAXCONTINUATIONPOINTS; + + /* Init start time to zero, the actual start time will be sampled in + * UA_Server_run_startup() */ + server->startTime = 0; + + /* Set a seed for non-cyptographic randomness */ +#ifndef UA_ENABLE_DETERMINISTIC_RNG + UA_random_seed((UA_UInt64)UA_DateTime_now()); +#endif + + /* Initialize the handling of repeated callbacks */ + UA_Timer_init(&server->timer); + + /* Initialized the linked list for delayed callbacks */ +#ifndef UA_ENABLE_MULTITHREADING + SLIST_INIT(&server->delayedCallbacks); +#endif + + /* Initialized the dispatch queue for worker threads */ +#ifdef UA_ENABLE_MULTITHREADING + SIMPLEQ_INIT(&server->dispatchQueue); +#endif + + /* Create Namespaces 0 and 1 */ + server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]); + server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/"); + UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]); + server->namespacesSize = 2; + + /* Initialized SecureChannel and Session managers */ + UA_SecureChannelManager_init(&server->secureChannelManager, server); + UA_SessionManager_init(&server->sessionManager, server); + + /* Add a regular callback for cleanup and maintenance */ + UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_Server_cleanup, NULL, + 10000, NULL); + + /* Initialized discovery database */ +#ifdef UA_ENABLE_DISCOVERY + LIST_INIT(&server->registeredServers); + server->registeredServersSize = 0; + LIST_INIT(&server->periodicServerRegisterCallbacks); + server->registerServerCallback = NULL; + server->registerServerCallbackData = NULL; +#endif + + /* Initialize multicast discovery */ +#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) + server->mdnsDaemon = NULL; +#ifdef _WIN32 + server->mdnsSocket = INVALID_SOCKET; +#else + server->mdnsSocket = -1; +#endif + server->mdnsMainSrvAdded = UA_FALSE; + if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) + initMulticastDiscoveryServer(server); + + LIST_INIT(&server->serverOnNetwork); + server->serverOnNetworkSize = 0; + server->serverOnNetworkRecordIdCounter = 0; + server->serverOnNetworkRecordIdLastReset = UA_DateTime_now(); + memset(server->serverOnNetworkHash, 0, + sizeof(struct serverOnNetwork_hash_entry*) * SERVER_ON_NETWORK_HASH_PRIME); + + server->serverOnNetworkCallback = NULL; + server->serverOnNetworkCallbackData = NULL; +#endif + + /* Initialize namespace 0*/ + UA_StatusCode retVal = UA_Server_initNS0(server); + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(config->logger, UA_LOGCATEGORY_SERVER, + "Initialization of Namespace 0 failed with %s. " + "See previous outputs for any error messages.", + UA_StatusCode_name(retVal)); + UA_Server_delete(server); + return NULL; + } + + return server; +} + +/*****************/ +/* Repeated Jobs */ +/*****************/ + +UA_StatusCode +UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_UInt32 interval, + UA_UInt64 *callbackId) { + return UA_Timer_addRepeatedCallback(&server->timer, (UA_TimerCallback)callback, + data, interval, callbackId); +} + +UA_StatusCode +UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, + UA_UInt32 interval) { + return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval); +} + +UA_StatusCode +UA_Server_removeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId) { + return UA_Timer_removeRepeatedCallback(&server->timer, callbackId); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Thomas Bender + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017 (c) Henrik Norrman + */ + + +/*****************/ +/* Node Creation */ +/*****************/ + +static UA_StatusCode +addNode_begin(UA_Server *server, UA_NodeClass nodeClass, + UA_UInt32 nodeId, char *name, void *attributes, + const UA_DataType *attributesType) { + UA_AddNodesItem item; + UA_AddNodesItem_init(&item); + 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_NodeId parentNode = UA_NODEID_NULL; + UA_NodeId referenceType = UA_NODEID_NULL; + return Operation_addNode_begin(server, &server->adminSession, NULL, &item, + &parentNode, &referenceType, NULL); +} + +static UA_StatusCode +addNode_finish(UA_Server *server, UA_UInt32 nodeId, + UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) { + UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId); + UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId); + UA_ExpandedNodeId targetId = UA_EXPANDEDNODEID_NUMERIC(0, parentNodeId); + UA_StatusCode retval = UA_Server_addReference(server, sourceId, refTypeId, targetId, UA_FALSE); + if (retval != UA_STATUSCODE_GOOD) + return retval; + + + UA_NodeId node = UA_NODEID_NUMERIC(0, nodeId); + return Operation_addNode_finish(server, &server->adminSession, &node); +} + +static UA_StatusCode +addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid, + UA_Boolean isAbstract, UA_UInt32 parentid) { + UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("", name); + attr.isAbstract = isAbstract; + return UA_Server_addDataTypeNode(server, UA_NODEID_NUMERIC(0, datatypeid), + UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, + UA_QUALIFIEDNAME(0, name), attr, NULL, NULL); +} + +static UA_StatusCode +addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid, + UA_Boolean isAbstract, UA_UInt32 parentid) { + UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("", name); + attr.isAbstract = isAbstract; + return UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(0, objecttypeid), + UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, + UA_QUALIFIEDNAME(0, name), attr, NULL, NULL); +} + +static UA_StatusCode +addObjectNode(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 +addReferenceTypeNode(UA_Server *server, char* name, char *inverseName, UA_UInt32 referencetypeid, + UA_Boolean isabstract, UA_Boolean symmetric, UA_UInt32 parentid) { + UA_ReferenceTypeAttributes reference_attr = UA_ReferenceTypeAttributes_default; + reference_attr.displayName = UA_LOCALIZEDTEXT("", name); + reference_attr.isAbstract = isabstract; + reference_attr.symmetric = symmetric; + if(inverseName) + reference_attr.inverseName = UA_LOCALIZEDTEXT("", inverseName); + return UA_Server_addReferenceTypeNode(server, UA_NODEID_NUMERIC(0, referencetypeid), + UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, + UA_QUALIFIEDNAME(0, name), reference_attr, NULL, NULL); +} + +static UA_StatusCode +addVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid, + UA_Boolean isAbstract, UA_Int32 valueRank, UA_UInt32 dataType, + const UA_DataType *type, UA_UInt32 parentid) { + UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("", name); + attr.dataType = UA_NODEID_NUMERIC(0, dataType); + attr.isAbstract = isAbstract; + attr.valueRank = valueRank; + + if(type) { + UA_STACKARRAY(UA_Byte, tempVal, type->memSize); + UA_init(tempVal, type); + UA_Variant_setScalar(&attr.value, tempVal, type); + return UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, variabletypeid), + UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, + UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL); + } + return UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, variabletypeid), + UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, + UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL); +} + +/**********************/ +/* Create Namespace 0 */ +/**********************/ + +/* Creates the basic nodes which are expected by the nodeset compiler to be + * already created. This is necessary to reduce the dependencies for the nodeset + * compiler. */ +static UA_StatusCode +UA_Server_createNS0_base(UA_Server *server) { + + UA_StatusCode ret = UA_STATUSCODE_GOOD; + /*********************************/ + /* Bootstrap reference hierarchy */ + /*********************************/ + + /* Bootstrap References and HasSubtype */ + UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default; + references_attr.displayName = UA_LOCALIZEDTEXT("", "References"); + references_attr.isAbstract = true; + references_attr.symmetric = true; + references_attr.inverseName = UA_LOCALIZEDTEXT("", "References"); + ret |= addNode_begin(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_REFERENCES, "References", + &references_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); + + UA_ReferenceTypeAttributes hassubtype_attr = UA_ReferenceTypeAttributes_default; + hassubtype_attr.displayName = UA_LOCALIZEDTEXT("", "HasSubtype"); + hassubtype_attr.isAbstract = false; + hassubtype_attr.symmetric = false; + hassubtype_attr.inverseName = UA_LOCALIZEDTEXT("", "HasSupertype"); + ret |= addNode_begin(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype", + &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); + + ret |= addReferenceTypeNode(server, "HierarchicalReferences", NULL, + UA_NS0ID_HIERARCHICALREFERENCES, + true, false, UA_NS0ID_REFERENCES); + + ret |= addReferenceTypeNode(server, "NonHierarchicalReferences", NULL, + UA_NS0ID_NONHIERARCHICALREFERENCES, + true, false, UA_NS0ID_REFERENCES); + + ret |= addReferenceTypeNode(server, "HasChild", NULL, UA_NS0ID_HASCHILD, + true, false, UA_NS0ID_HIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "Organizes", "OrganizedBy", UA_NS0ID_ORGANIZES, + false, false, UA_NS0ID_HIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "HasEventSource", "EventSourceOf", UA_NS0ID_HASEVENTSOURCE, + false, false, UA_NS0ID_HIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "HasModellingRule", "ModellingRuleOf", UA_NS0ID_HASMODELLINGRULE, + false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "HasEncoding", "EncodingOf", UA_NS0ID_HASENCODING, + false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "HasDescription", "DescriptionOf", UA_NS0ID_HASDESCRIPTION, + false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "HasTypeDefinition", "TypeDefinitionOf", UA_NS0ID_HASTYPEDEFINITION, + false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "GeneratesEvent", "GeneratedBy", UA_NS0ID_GENERATESEVENT, + false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + + ret |= addReferenceTypeNode(server, "Aggregates", "AggregatedBy", UA_NS0ID_AGGREGATES, + false, false, UA_NS0ID_HASCHILD); + + /* Complete bootstrap of HasSubtype */ + ret |= addNode_finish(server, UA_NS0ID_HASSUBTYPE, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE); + + ret |= addReferenceTypeNode(server, "HasProperty", "PropertyOf", UA_NS0ID_HASPROPERTY, + false, false, UA_NS0ID_AGGREGATES); + + ret |= addReferenceTypeNode(server, "HasComponent", "ComponentOf", UA_NS0ID_HASCOMPONENT, + false, false, UA_NS0ID_AGGREGATES); + + ret |= addReferenceTypeNode(server, "HasNotifier", "NotifierOf", UA_NS0ID_HASNOTIFIER, + false, false, UA_NS0ID_HASEVENTSOURCE); + + ret |= addReferenceTypeNode(server, "HasOrderedComponent", "OrderedComponentOf", + UA_NS0ID_HASORDEREDCOMPONENT, false, false, UA_NS0ID_HASCOMPONENT); + + /**************/ + /* Data Types */ + /**************/ + + /* Bootstrap BaseDataType */ + UA_DataTypeAttributes basedatatype_attr = UA_DataTypeAttributes_default; + basedatatype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataType"); + basedatatype_attr.isAbstract = true; + ret |= addNode_begin(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType", + &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]); + + ret |= addDataTypeNode(server, "Number", UA_NS0ID_NUMBER, true, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "Integer", UA_NS0ID_INTEGER, true, UA_NS0ID_NUMBER); + ret |= addDataTypeNode(server, "UInteger", UA_NS0ID_UINTEGER, true, UA_NS0ID_NUMBER); + ret |= addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "SByte", UA_NS0ID_SBYTE, false, UA_NS0ID_INTEGER); + ret |= addDataTypeNode(server, "Byte", UA_NS0ID_BYTE, false, UA_NS0ID_UINTEGER); + ret |= addDataTypeNode(server, "Int16", UA_NS0ID_INT16, false, UA_NS0ID_INTEGER); + ret |= addDataTypeNode(server, "UInt16", UA_NS0ID_UINT16, false, UA_NS0ID_UINTEGER); + ret |= addDataTypeNode(server, "Int32", UA_NS0ID_INT32, false, UA_NS0ID_INTEGER); + ret |= addDataTypeNode(server, "UInt32", UA_NS0ID_UINT32, false, UA_NS0ID_UINTEGER); + ret |= addDataTypeNode(server, "Int64", UA_NS0ID_INT64, false, UA_NS0ID_INTEGER); + ret |= addDataTypeNode(server, "UInt64", UA_NS0ID_UINT64, false, UA_NS0ID_UINTEGER); + ret |= addDataTypeNode(server, "Float", UA_NS0ID_FLOAT, false, UA_NS0ID_NUMBER); + ret |= addDataTypeNode(server, "Double", UA_NS0ID_DOUBLE, false, UA_NS0ID_NUMBER); + ret |= addDataTypeNode(server, "DateTime", UA_NS0ID_DATETIME, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "String", UA_NS0ID_STRING, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "ByteString", UA_NS0ID_BYTESTRING, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "Guid", UA_NS0ID_GUID, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "XmlElement", UA_NS0ID_XMLELEMENT, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "NodeId", UA_NS0ID_NODEID, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "ExpandedNodeId", UA_NS0ID_EXPANDEDNODEID, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "QualifiedName", UA_NS0ID_QUALIFIEDNAME, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "LocalizedText", UA_NS0ID_LOCALIZEDTEXT, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "StatusCode", UA_NS0ID_STATUSCODE, false, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "Structure", UA_NS0ID_STRUCTURE, true, UA_NS0ID_BASEDATATYPE); + ret |= addDataTypeNode(server, "Decimal128", UA_NS0ID_DECIMAL128, false, UA_NS0ID_NUMBER); + + ret |= addDataTypeNode(server, "Duration", UA_NS0ID_DURATION, false, UA_NS0ID_DOUBLE); + ret |= addDataTypeNode(server, "UtcTime", UA_NS0ID_UTCTIME, false, UA_NS0ID_DATETIME); + ret |= addDataTypeNode(server, "LocaleId", UA_NS0ID_LOCALEID, false, UA_NS0ID_STRING); + + /*****************/ + /* VariableTypes */ + /*****************/ + + /* Bootstrap BaseVariableType */ + UA_VariableTypeAttributes basevar_attr = UA_VariableTypeAttributes_default; + basevar_attr.displayName = UA_LOCALIZEDTEXT("", "BaseVariableType"); + basevar_attr.isAbstract = true; + basevar_attr.valueRank = UA_VALUERANK_ANY; + basevar_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE); + ret |= addNode_begin(server, UA_NODECLASS_VARIABLETYPE, UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType", + &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]); + + ret |= addVariableTypeNode(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE, + false, -2, UA_NS0ID_BASEDATATYPE, NULL, UA_NS0ID_BASEVARIABLETYPE); + + /***************/ + /* ObjectTypes */ + /***************/ + + /* Bootstrap BaseObjectType */ + UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default; + baseobj_attr.displayName = UA_LOCALIZEDTEXT("", "BaseObjectType"); + ret |= addNode_begin(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType", + &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); + + ret |= addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, + false, UA_NS0ID_BASEOBJECTTYPE); + + /******************/ + /* Root and below */ + /******************/ + + ret |= addObjectNode(server, "Root", UA_NS0ID_ROOTFOLDER, 0, 0, UA_NS0ID_FOLDERTYPE); + + ret |= addObjectNode(server, "Objects", UA_NS0ID_OBJECTSFOLDER, UA_NS0ID_ROOTFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + + ret |= addObjectNode(server, "Types", UA_NS0ID_TYPESFOLDER, UA_NS0ID_ROOTFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + + ret |= addObjectNode(server, "ReferenceTypes", UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_TYPESFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + ret |= addNode_finish(server, UA_NS0ID_REFERENCES, UA_NS0ID_REFERENCETYPESFOLDER, + UA_NS0ID_ORGANIZES); + + ret |= addObjectNode(server, "DataTypes", UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_TYPESFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + + ret |= addNode_finish(server, UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER, + UA_NS0ID_ORGANIZES); + + ret |= addObjectNode(server, "VariableTypes", UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_TYPESFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + + ret |= addNode_finish(server, UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER, + UA_NS0ID_ORGANIZES); + + ret |= addObjectNode(server, "ObjectTypes", UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_TYPESFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + ret |= addNode_finish(server, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER, + UA_NS0ID_ORGANIZES); + + ret |= addObjectNode(server, "EventTypes", UA_NS0ID_EVENTTYPESFOLDER, UA_NS0ID_TYPESFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + + ret |= addObjectNode(server, "Views", UA_NS0ID_VIEWSFOLDER, UA_NS0ID_ROOTFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); + + if(ret != UA_STATUSCODE_GOOD) + return UA_STATUSCODE_BADINTERNALERROR; + return UA_STATUSCODE_GOOD; +} + +/****************/ +/* Data Sources */ +/****************/ + +static UA_StatusCode +readStatus(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; + } + + UA_ServerStatusDataType *statustype = UA_ServerStatusDataType_new(); + statustype->startTime = server->startTime; + statustype->currentTime = UA_DateTime_now(); + statustype->state = UA_SERVERSTATE_RUNNING; + statustype->secondsTillShutdown = 0; + UA_BuildInfo_copy(&server->config.buildInfo, &statustype->buildInfo); + + value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE]; + value->value.arrayLength = 0; + value->value.data = statustype; + value->value.arrayDimensionsSize = 0; + value->value.arrayDimensions = NULL; + value->hasValue = true; + if(sourceTimestamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +readServiceLevel(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp, + const UA_NumericRange *range, UA_DataValue *value) { + if(range) { + value->hasStatus = true; + value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; + return UA_STATUSCODE_GOOD; + } + + value->value.type = &UA_TYPES[UA_TYPES_BYTE]; + value->value.arrayLength = 0; + UA_Byte *byte = UA_Byte_new(); + *byte = 255; + value->value.data = byte; + value->value.arrayDimensionsSize = 0; + value->value.arrayDimensions = NULL; + value->hasValue = true; + if(includeSourceTimeStamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +readAuditing(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp, + const UA_NumericRange *range, UA_DataValue *value) { + if(range) { + value->hasStatus = true; + value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; + return UA_STATUSCODE_GOOD; + } + + value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN]; + value->value.arrayLength = 0; + UA_Boolean *boolean = UA_Boolean_new(); + *boolean = false; + value->value.data = boolean; + value->value.arrayDimensionsSize = 0; + value->value.arrayDimensions = NULL; + value->hasValue = true; + if(includeSourceTimeStamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +readNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp, + const UA_NumericRange *range, + UA_DataValue *value) { + if(range) { + value->hasStatus = true; + value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; + return UA_STATUSCODE_GOOD; + } + UA_StatusCode retval; + retval = UA_Variant_setArrayCopy(&value->value, server->namespaces, + server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + value->hasValue = true; + if(includeSourceTimeStamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +writeNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, + const UA_NodeId *nodeid, void *nodeContext, const UA_NumericRange *range, + const UA_DataValue *value) { + /* Check the data type */ + if(!value->hasValue || + value->value.type != &UA_TYPES[UA_TYPES_STRING]) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* Check that the variant is not empty */ + if(!value->value.data) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* TODO: Writing with a range is not implemented */ + if(range) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_String *newNamespaces = (UA_String*)value->value.data; + size_t newNamespacesSize = value->value.arrayLength; + + /* Test if we append to the existing namespaces */ + if(newNamespacesSize <= server->namespacesSize) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* Test if the existing namespaces are unchanged */ + for(size_t i = 0; i < server->namespacesSize; ++i) { + if(!UA_String_equal(&server->namespaces[i], &newNamespaces[i])) + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Add namespaces */ + for(size_t i = server->namespacesSize; i < newNamespacesSize; ++i) + addNamespace(server, newNamespaces[i]); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +readCurrentTime(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; + } + UA_DateTime currentTime = UA_DateTime_now(); + UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, ¤tTime, + &UA_TYPES[UA_TYPES_DATETIME]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + value->hasValue = true; + if(sourceTimeStamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = currentTime; + } + return UA_STATUSCODE_GOOD; +} + +#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) +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_Session *session = UA_SessionManager_getSessionById(&server->sessionManager, sessionId); + if(!session) + return UA_STATUSCODE_BADINTERNALERROR; + if (inputSize == 0 || !input[0].data) + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data)); + UA_Subscription* subscription = UA_Session_getSubscriptionById(session, subscriptionId); + 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; + } + else + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + UA_UInt32 sizeOfOutput = 0; + UA_MonitoredItem* monitoredItem; + LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { + ++sizeOfOutput; + } + if(sizeOfOutput==0) + 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]); + UA_UInt32 i = 0; + LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { + clientHandles[i] = monitoredItem->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]); + return UA_STATUSCODE_GOOD; +} +#endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */ + +static UA_StatusCode +writeNs0Variable(UA_Server *server, UA_UInt32 id, void *v, const UA_DataType *type) { + UA_Variant var; + UA_Variant_init(&var); + UA_Variant_setScalar(&var, v, type); + return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var); +} + +static UA_StatusCode +writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, + size_t length, const UA_DataType *type) { + UA_Variant var; + UA_Variant_init(&var); + UA_Variant_setArray(&var, v, length, type); + return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var); +} + +/* Initialize the nodeset 0 by using the generated code of the nodeset compiler. + * This also initialized the data sources for various variables, such as for + * 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; + + /* Load nodes and references generated from the XML ns0 definition */ + server->bootstrapNS0 = true; + retVal = ua_namespace0(server); + server->bootstrapNS0 = false; + if(retVal != UA_STATUSCODE_GOOD) + return retVal; + + /* NamespaceArray */ + UA_DataSource namespaceDataSource = {readNamespaces, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), + namespaceDataSource); + + /* ServerArray */ + retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY, + &server->config.applicationDescription.applicationUri, + 1, &UA_TYPES[UA_TYPES_STRING]); + + /* LocaleIdArray */ + UA_LocaleId locale_en = UA_STRING("en"); + retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY, + &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]); + + /* MaxBrowseContinuationPoints */ + UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS, + &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); + + /* ServerProfileArray */ + UA_String profileArray[4]; + UA_UInt16 profileArraySize = 0; +#define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING_ALLOC(x) + ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NanoEmbeddedDevice"); +#ifdef UA_ENABLE_NODEMANAGEMENT + ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement"); +#endif +#ifdef UA_ENABLE_METHODCALLS + ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods"); +#endif +#ifdef UA_ENABLE_SUBSCRIPTIONS + ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/EmbeddedDataChangeSubscription"); +#endif + + retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY, + profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]); + for(int i=0; i<profileArraySize; i++) { + UA_String_deleteMembers(&profileArray[i]); + } + + /* MaxQueryContinuationPoints */ + UA_UInt16 maxQueryContinuationPoints = 0; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS, + &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); + + /* MaxHistoryContinuationPoints */ + UA_UInt16 maxHistoryContinuationPoints = 0; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS, + &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); + + /* MinSupportedSampleRate */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE, + &server->config.samplingIntervalLimits.min, &UA_TYPES[UA_TYPES_DURATION]); + + /* 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 */ + UA_Boolean enabledFlag = false; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG, + &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerStatus */ + UA_DataSource serverStatus = {readStatus, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), serverStatus); + + /* StartTime will be sampled in UA_Server_run_startup()*/ + + /* CurrentTime */ + UA_DataSource currentTime = {readCurrentTime, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), currentTime); + + /* State */ + UA_ServerState state = UA_SERVERSTATE_RUNNING; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_STATE, + &state, &UA_TYPES[UA_TYPES_SERVERSTATE]); + + /* BuildInfo */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, + &server->config.buildInfo, &UA_TYPES[UA_TYPES_BUILDINFO]); + + /* BuildInfo - ProductUri */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI, + &server->config.buildInfo.productUri, &UA_TYPES[UA_TYPES_STRING]); + + /* BuildInfo - ManufacturerName */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME, + &server->config.buildInfo.manufacturerName, &UA_TYPES[UA_TYPES_STRING]); + + /* BuildInfo - ProductName */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME, + &server->config.buildInfo.productName, &UA_TYPES[UA_TYPES_STRING]); + + /* BuildInfo - SoftwareVersion */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION, + &server->config.buildInfo.softwareVersion, &UA_TYPES[UA_TYPES_STRING]); + + /* BuildInfo - BuildNumber */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER, + &server->config.buildInfo.buildNumber, &UA_TYPES[UA_TYPES_STRING]); + + /* BuildInfo - BuildDate */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE, + &server->config.buildInfo.buildDate, &UA_TYPES[UA_TYPES_DATETIME]); + + /* SecondsTillShutdown */ + UA_UInt32 secondsTillShutdown = 0; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN, + &secondsTillShutdown, &UA_TYPES[UA_TYPES_UINT32]); + + /* ShutDownReason */ + UA_LocalizedText shutdownReason; + UA_LocalizedText_init(&shutdownReason); + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON, + &shutdownReason, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + + /* ServiceLevel */ + UA_DataSource serviceLevel = {readServiceLevel, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVICELEVEL), serviceLevel); + + /* Auditing */ + UA_DataSource auditing = {readAuditing, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_AUDITING), auditing); + + /* NamespaceArray */ + UA_DataSource nsarray_datasource = {readNamespaces, writeNamespaces}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), nsarray_datasource); + + /* Redundancy Support */ + UA_RedundancySupport redundancySupport = UA_REDUNDANCYSUPPORT_NONE; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT, + &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]); + + /* ServerCapabilities - OperationLimits - MaxNodesPerRead */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD, + &server->config.maxNodesPerRead, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - maxNodesPerWrite */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE, + &server->config.maxNodesPerWrite, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - MaxNodesPerMethodCall */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL, + &server->config.maxNodesPerMethodCall, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - MaxNodesPerBrowse */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE, + &server->config.maxNodesPerBrowse, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - MaxNodesPerRegisterNodes */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES, + &server->config.maxNodesPerRegisterNodes, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - MaxNodesPerTranslateBrowsePathsToNodeIds */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS, + &server->config.maxNodesPerTranslateBrowsePathsToNodeIds, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - MaxNodesPerNodeManagement */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT, + &server->config.maxNodesPerNodeManagement, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - OperationLimits - MaxMonitoredItemsPerCall */ + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL, + &server->config.maxMonitoredItemsPerCall, &UA_TYPES[UA_TYPES_UINT32]); + +#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) + retVal |= UA_Server_setMethodNode_callback(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), readMonitoredItems); +#endif + return retVal; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/build/src_generated/ua_namespace0.c" ***********************************/ + +/* WARNING: This is a generated file. + * Any manual changes will be overwritten. */ + + + +/* HasHistoricalConfiguration - ns=0;i=56 */ + +static UA_StatusCode function_ua_namespace0_0_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"); +attr.description = UA_LOCALIZEDTEXT("", "The type for a reference to the historical configuration for a data variable."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, +UA_NODEID_NUMERIC(ns[0], 56), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "HasHistoricalConfiguration"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 56), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 44), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_0_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 56) +); +} + +/* HasEffect - ns=0;i=54 */ + +static UA_StatusCode function_ua_namespace0_1_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"); +attr.description = UA_LOCALIZEDTEXT("", "The type for a reference to an event that may be raised when a transition occurs."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, +UA_NODEID_NUMERIC(ns[0], 54), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "HasEffect"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 54), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 32), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_1_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 54) +); +} + +/* ToState - ns=0;i=52 */ + +static UA_StatusCode function_ua_namespace0_2_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"); +attr.description = UA_LOCALIZEDTEXT("", "The type for a reference to the state after a transition."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, +UA_NODEID_NUMERIC(ns[0], 52), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ToState"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 52), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 32), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_2_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 52) +); +} + +/* HasCause - ns=0;i=53 */ + +static UA_StatusCode function_ua_namespace0_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"); +attr.description = UA_LOCALIZEDTEXT("", "The type for a reference to a method that can cause a transition to occur."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, +UA_NODEID_NUMERIC(ns[0], 53), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "HasCause"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 53), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 32), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_3_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 53) +); +} + +/* FromState - ns=0;i=51 */ + +static UA_StatusCode function_ua_namespace0_4_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"); +attr.description = UA_LOCALIZEDTEXT("", "The type for a reference to the state before a transition."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE, +UA_NODEID_NUMERIC(ns[0], 51), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "FromState"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 51), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 32), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_4_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 51) +); +} + +/* EnumValueType - ns=0;i=7594 */ + +static UA_StatusCode function_ua_namespace0_5_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.description = UA_LOCALIZEDTEXT("", "A mapping between a value of an enumerated type and a name and description."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 7594), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "EnumValueType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7594), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 22), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_5_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 7594) +); +} + +/* ServerCapabilitiesType - ns=0;i=2013 */ + +static UA_StatusCode function_ua_namespace0_6_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilitiesType"); +attr.description = UA_LOCALIZEDTEXT("", "Describes the capabilities supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2013), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerCapabilitiesType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2013), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_6_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2013) +); +} + +/* OperationLimitsType - ns=0;i=11564 */ + +static UA_StatusCode function_ua_namespace0_7_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.description = UA_LOCALIZEDTEXT("", "Identifies the operation limits imposed by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 11564), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "OperationLimitsType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11564), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 61), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_7_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11564) +); +} + +/* OperationLimits - ns=0;i=11551 */ + +static UA_StatusCode function_ua_namespace0_8_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits"); +attr.description = UA_LOCALIZEDTEXT("", "Defines the limits supported by the server for different operations."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 11551), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "OperationLimits"), +UA_NODEID_NUMERIC(ns[0], 11564), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11551), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2013), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_8_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11551) +); +} + +/* BuildInfo - ns=0;i=338 */ + +static UA_StatusCode function_ua_namespace0_9_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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 338), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "BuildInfo"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 338), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 22), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_9_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 338) +); +} + +/* ServerType - ns=0;i=2004 */ + +static UA_StatusCode function_ua_namespace0_10_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerType"); +attr.description = UA_LOCALIZEDTEXT("", "Specifies the current status and capabilities of the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2004), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2004), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_10_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2004) +); +} + +/* Server - ns=0;i=2253 */ + +static UA_StatusCode function_ua_namespace0_11_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"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2253), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Server"), +UA_NODEID_NUMERIC(ns[0], 2004), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2253), UA_NODEID_NUMERIC(ns[0], 35), UA_EXPANDEDNODEID_NUMERIC(ns[0], 85), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_11_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2253) +); +} + +/* GetMonitoredItems - ns=0;i=11492 */ + +static UA_StatusCode function_ua_namespace0_12_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"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD, +UA_NODEID_NUMERIC(ns[0], 11492), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "GetMonitoredItems"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11492), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +#else +return UA_STATUSCODE_GOOD; +#endif /* UA_ENABLE_METHODCALLS */ +} + +static UA_StatusCode function_ua_namespace0_12_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 */ +} + +/* ServerCapabilities - ns=0;i=2268 */ + +static UA_StatusCode function_ua_namespace0_13_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilities"); +attr.description = UA_LOCALIZEDTEXT("", "Describes capabilities supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2268), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerCapabilities"), +UA_NODEID_NUMERIC(ns[0], 2013), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2268), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_13_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2268) +); +} + +/* AggregateFunctions - ns=0;i=2997 */ + +static UA_StatusCode function_ua_namespace0_14_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions"); +attr.description = UA_LOCALIZEDTEXT("", "A folder for the real time aggregates supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2997), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"), +UA_NODEID_NUMERIC(ns[0], 61), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2997), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_14_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2997) +); +} + +/* ModellingRules - ns=0;i=2996 */ + +static UA_StatusCode function_ua_namespace0_15_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRules"); +attr.description = UA_LOCALIZEDTEXT("", "A folder for the modelling rules supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2996), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ModellingRules"), +UA_NODEID_NUMERIC(ns[0], 61), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2996), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_15_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_ua_namespace0_16_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits"); +attr.description = UA_LOCALIZEDTEXT("", "Defines the limits supported by the server for different operations."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 11704), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "OperationLimits"), +UA_NODEID_NUMERIC(ns[0], 11564), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11704), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_16_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11704) +); +} + +/* ServerDiagnosticsSummaryType - ns=0;i=2150 */ + +static UA_StatusCode function_ua_namespace0_17_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = (UA_Int32)-2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryType"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 2150), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummaryType"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2150), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 63), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_17_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2150) +); +} + +/* PublishingIntervalCount - ns=0;i=2159 */ + +static UA_StatusCode function_ua_namespace0_18_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2159), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2159), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_18_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2159) +); +} + +/* SecurityRejectedSessionCount - ns=0;i=2154 */ + +static UA_StatusCode function_ua_namespace0_19_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2154), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2154), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_19_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2154) +); +} + +/* SecurityRejectedRequestsCount - ns=0;i=2162 */ + +static UA_StatusCode function_ua_namespace0_20_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2162), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2162), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_20_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2162) +); +} + +/* RejectedRequestsCount - ns=0;i=2163 */ + +static UA_StatusCode function_ua_namespace0_21_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2163), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2163), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_21_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2163) +); +} + +/* RejectedSessionCount - ns=0;i=2155 */ + +static UA_StatusCode function_ua_namespace0_22_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2155), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2155), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_22_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2155) +); +} + +/* CumulatedSubscriptionCount - ns=0;i=2161 */ + +static UA_StatusCode function_ua_namespace0_23_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2161), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2161), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_23_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2161) +); +} + +/* CumulatedSessionCount - ns=0;i=2153 */ + +static UA_StatusCode function_ua_namespace0_24_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2153), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2153), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_24_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2153) +); +} + +/* CurrentSessionCount - ns=0;i=2152 */ + +static UA_StatusCode function_ua_namespace0_25_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2152), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2152), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_25_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2152) +); +} + +/* ServerViewCount - ns=0;i=2151 */ + +static UA_StatusCode function_ua_namespace0_26_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2151), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerViewCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2151), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_26_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2151) +); +} + +/* SessionAbortCount - ns=0;i=2157 */ + +static UA_StatusCode function_ua_namespace0_27_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2157), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2157), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_27_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2157) +); +} + +/* SessionTimeoutCount - ns=0;i=2156 */ + +static UA_StatusCode function_ua_namespace0_28_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2156), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2156), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_28_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2156) +); +} + +/* CurrentSubscriptionCount - ns=0;i=2160 */ + +static UA_StatusCode function_ua_namespace0_29_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2160), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2160), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2150), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_29_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2160) +); +} + +/* BuildInfoType - ns=0;i=3051 */ + +static UA_StatusCode function_ua_namespace0_30_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = (UA_Int32)-2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfoType"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 3051), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "BuildInfoType"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 3051), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 63), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_30_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3051) +); +} + +/* Image - ns=0;i=30 */ + +static UA_StatusCode function_ua_namespace0_31_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"); +attr.description = UA_LOCALIZEDTEXT("", "Describes a value that is an image encoded as a string of bytes."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 30), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Image"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 30), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 15), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_31_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 30) +); +} + +/* Decimal - ns=0;i=50 */ + +static UA_StatusCode function_ua_namespace0_32_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.description = UA_LOCALIZEDTEXT("", "Describes an arbitrary precision decimal value."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 50), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Decimal"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 50), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 26), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_32_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 50) +); +} + +/* Enumeration - ns=0;i=29 */ + +static UA_StatusCode function_ua_namespace0_33_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"); +attr.description = UA_LOCALIZEDTEXT("", "Describes a value that is an enumerated DataType."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 29), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Enumeration"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 29), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 24), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_33_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 29) +); +} + +/* NamingRuleType - ns=0;i=120 */ + +static UA_StatusCode function_ua_namespace0_34_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.description = UA_LOCALIZEDTEXT("", "Describes a value that specifies the significance of the BrowseName for an instance declaration."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 120), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "NamingRuleType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 120), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 29), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_34_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 120) +); +} + +/* RedundancySupport - ns=0;i=851 */ + +static UA_StatusCode function_ua_namespace0_35_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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 851), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 851), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 29), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_35_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 851) +); +} + +/* ServerState - ns=0;i=852 */ + +static UA_StatusCode function_ua_namespace0_36_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerState"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 852), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerState"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 852), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 29), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_36_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 852) +); +} + +/* DiagnosticInfo - ns=0;i=25 */ + +static UA_StatusCode function_ua_namespace0_37_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "DiagnosticInfo"); +attr.description = UA_LOCALIZEDTEXT("", "Describes a value that is a structure containing diagnostics associated with a StatusCode."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 25), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DiagnosticInfo"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 25), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 24), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_37_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 25) +); +} + +/* DataValue - ns=0;i=23 */ + +static UA_StatusCode function_ua_namespace0_38_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "DataValue"); +attr.description = UA_LOCALIZEDTEXT("", "Describes a value that is a structure containing a value, a status code and timestamps."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 23), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataValue"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 23), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 24), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_38_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 23) +); +} + +/* ServerRedundancyType - ns=0;i=2034 */ + +static UA_StatusCode function_ua_namespace0_39_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancyType"); +attr.description = UA_LOCALIZEDTEXT("", "A base type for an object that describe how a server supports redundancy."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2034), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerRedundancyType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2034), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_39_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2034) +); +} + +/* ServerRedundancy - ns=0;i=2296 */ + +static UA_StatusCode function_ua_namespace0_40_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancy"); +attr.description = UA_LOCALIZEDTEXT("", "Describes the redundancy capabilities of the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2296), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerRedundancy"), +UA_NODEID_NUMERIC(ns[0], 2034), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2296), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_40_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2296) +); +} + +/* PropertyType - ns=0;i=68 */ + +static UA_StatusCode function_ua_namespace0_41_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = (UA_Int32)-2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.displayName = UA_LOCALIZEDTEXT("", "PropertyType"); +attr.description = UA_LOCALIZEDTEXT("", "The type for variable that represents a property of another node."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 68), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "PropertyType"), +UA_NODEID_NUMERIC(ns[0], 62), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 68), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 62), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_41_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 68) +); +} + +/* MaxBrowseContinuationPoints - ns=0;i=2735 */ + +static UA_StatusCode function_ua_namespace0_42_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.dataType = UA_NODEID_NUMERIC(ns[0], 5); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT16]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxBrowseContinuationPoints"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of continuation points for Browse operations per session."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2735), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxBrowseContinuationPoints"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2735), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_42_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2735) +); +} + +/* MaxNodesPerBrowse - ns=0;i=11710 */ + +static UA_StatusCode function_ua_namespace0_43_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Browse request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11710), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11710), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_43_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11710) +); +} + +/* MaxNodesPerWrite - ns=0;i=11707 */ + +static UA_StatusCode function_ua_namespace0_44_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Write request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11707), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11707), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_44_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11707) +); +} + +/* Auditing - ns=0;i=2994 */ + +static UA_StatusCode function_ua_namespace0_45_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.dataType = UA_NODEID_NUMERIC(ns[0], 1); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_BOOLEAN]); +attr.displayName = UA_LOCALIZEDTEXT("", "Auditing"); +attr.description = UA_LOCALIZEDTEXT("", "A flag indicating whether the server is currently generating audit events."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2994), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Auditing"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2994), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_45_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2994) +); +} + +/* MaxNodesPerRead - ns=0;i=11565 */ + +static UA_StatusCode function_ua_namespace0_46_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Read request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11565), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11565), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_46_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11565) +); +} + +/* MaxNodesPerWrite - ns=0;i=11567 */ + +static UA_StatusCode function_ua_namespace0_47_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Write request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11567), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11567), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_47_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11567) +); +} + +/* RedundancySupport - ns=0;i=2035 */ + +static UA_StatusCode function_ua_namespace0_48_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.dataType = UA_NODEID_NUMERIC(ns[0], 851); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]); +attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); +attr.description = UA_LOCALIZEDTEXT("", "Indicates what style of redundancy is supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2035), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2035), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2034), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_48_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2035) +); +} + +/* MaxNodesPerMethodCall - ns=0;i=11569 */ + +static UA_StatusCode function_ua_namespace0_49_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Call request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11569), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11569), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_49_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11569) +); +} + +/* MaxNodesPerMethodCall - ns=0;i=11709 */ + +static UA_StatusCode function_ua_namespace0_50_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Call request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11709), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11709), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_50_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11709) +); +} + +/* NamespaceArray - ns=0;i=2255 */ + +static UA_StatusCode function_ua_namespace0_51_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setArray(&attr.value, NULL, (UA_Int32) 0, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceArray"); +attr.description = UA_LOCALIZEDTEXT("", "The list of namespace URIs used by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2255), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "NamespaceArray"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2255), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_51_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2255) +); +} + +/* ServerArray - ns=0;i=2254 */ + +static UA_StatusCode function_ua_namespace0_52_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setArray(&attr.value, NULL, (UA_Int32) 0, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerArray"); +attr.description = UA_LOCALIZEDTEXT("", "The list of server URIs used by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2254), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerArray"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2254), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_52_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2254) +); +} + +/* MinSupportedSampleRate - ns=0;i=2272 */ + +static UA_StatusCode function_ua_namespace0_53_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.dataType = UA_NODEID_NUMERIC(ns[0], 290); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_DOUBLE]); +attr.displayName = UA_LOCALIZEDTEXT("", "MinSupportedSampleRate"); +attr.description = UA_LOCALIZEDTEXT("", "The minimum sampling interval supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2272), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MinSupportedSampleRate"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2272), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_53_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2272) +); +} + +/* LocaleIdArray - ns=0;i=2271 */ + +static UA_StatusCode function_ua_namespace0_54_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 295); +UA_Variant_setArray(&attr.value, NULL, (UA_Int32) 0, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIdArray"); +attr.description = UA_LOCALIZEDTEXT("", "A list of locales supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2271), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "LocaleIdArray"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2271), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_54_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2271) +); +} + +/* EnumValues - ns=0;i=12169 */ + +static UA_StatusCode function_ua_namespace0_55_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594); + +struct { + UA_Int64 Value; + UA_LocalizedText DisplayName; + UA_LocalizedText Description; +} variablenode_ns_0_i_12169_EnumValueType_0_0_struct; +UA_ExtensionObject *variablenode_ns_0_i_12169_EnumValueType_0_0 = UA_ExtensionObject_new(); +if (!variablenode_ns_0_i_12169_EnumValueType_0_0) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_12169_EnumValueType_0_0_struct.Value = (UA_Int64) 1; +variablenode_ns_0_i_12169_EnumValueType_0_0_struct.DisplayName = UA_LOCALIZEDTEXT("", "Mandatory"); +variablenode_ns_0_i_12169_EnumValueType_0_0_struct.Description = UA_LOCALIZEDTEXT("", "The BrowseName must appear in all instances of the type."); +variablenode_ns_0_i_12169_EnumValueType_0_0->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; +variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.typeId = UA_NODEID_NUMERIC(0, 8251); +retVal |= UA_ByteString_allocBuffer(&variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body, 65000); +UA_Byte *posvariablenode_ns_0_i_12169_EnumValueType_0_0 = variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.data; +const UA_Byte *endvariablenode_ns_0_i_12169_EnumValueType_0_0 = &variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.data[65000]; +{ +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_0_0_struct.Value, &UA_TYPES[UA_TYPES_INT64], &posvariablenode_ns_0_i_12169_EnumValueType_0_0, &endvariablenode_ns_0_i_12169_EnumValueType_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_0_0_struct.DisplayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_12169_EnumValueType_0_0, &endvariablenode_ns_0_i_12169_EnumValueType_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_0_0_struct.Description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_12169_EnumValueType_0_0, &endvariablenode_ns_0_i_12169_EnumValueType_0_0, NULL, NULL); +} +size_t variablenode_ns_0_i_12169_EnumValueType_0_0_encOffset = (uintptr_t)(posvariablenode_ns_0_i_12169_EnumValueType_0_0-variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.data); +variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.length = variablenode_ns_0_i_12169_EnumValueType_0_0_encOffset; +UA_Byte *variablenode_ns_0_i_12169_EnumValueType_0_0_newBody = (UA_Byte *) UA_malloc(variablenode_ns_0_i_12169_EnumValueType_0_0_encOffset); +if (!variablenode_ns_0_i_12169_EnumValueType_0_0_newBody) return UA_STATUSCODE_BADOUTOFMEMORY; +memcpy(variablenode_ns_0_i_12169_EnumValueType_0_0_newBody, variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.data, variablenode_ns_0_i_12169_EnumValueType_0_0_encOffset); +UA_Byte *variablenode_ns_0_i_12169_EnumValueType_0_0_oldBody = variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.data; +variablenode_ns_0_i_12169_EnumValueType_0_0->content.encoded.body.data = variablenode_ns_0_i_12169_EnumValueType_0_0_newBody; +UA_free(variablenode_ns_0_i_12169_EnumValueType_0_0_oldBody); + + +struct { + UA_Int64 Value; + UA_LocalizedText DisplayName; + UA_LocalizedText Description; +} variablenode_ns_0_i_12169_EnumValueType_1_0_struct; +UA_ExtensionObject *variablenode_ns_0_i_12169_EnumValueType_1_0 = UA_ExtensionObject_new(); +if (!variablenode_ns_0_i_12169_EnumValueType_1_0) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_12169_EnumValueType_1_0_struct.Value = (UA_Int64) 2; +variablenode_ns_0_i_12169_EnumValueType_1_0_struct.DisplayName = UA_LOCALIZEDTEXT("", "Optional"); +variablenode_ns_0_i_12169_EnumValueType_1_0_struct.Description = UA_LOCALIZEDTEXT("", "The BrowseName may appear in an instance of the type."); +variablenode_ns_0_i_12169_EnumValueType_1_0->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; +variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.typeId = UA_NODEID_NUMERIC(0, 8251); +retVal |= UA_ByteString_allocBuffer(&variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body, 65000); +UA_Byte *posvariablenode_ns_0_i_12169_EnumValueType_1_0 = variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.data; +const UA_Byte *endvariablenode_ns_0_i_12169_EnumValueType_1_0 = &variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.data[65000]; +{ +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_1_0_struct.Value, &UA_TYPES[UA_TYPES_INT64], &posvariablenode_ns_0_i_12169_EnumValueType_1_0, &endvariablenode_ns_0_i_12169_EnumValueType_1_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_1_0_struct.DisplayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_12169_EnumValueType_1_0, &endvariablenode_ns_0_i_12169_EnumValueType_1_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_1_0_struct.Description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_12169_EnumValueType_1_0, &endvariablenode_ns_0_i_12169_EnumValueType_1_0, NULL, NULL); +} +size_t variablenode_ns_0_i_12169_EnumValueType_1_0_encOffset = (uintptr_t)(posvariablenode_ns_0_i_12169_EnumValueType_1_0-variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.data); +variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.length = variablenode_ns_0_i_12169_EnumValueType_1_0_encOffset; +UA_Byte *variablenode_ns_0_i_12169_EnumValueType_1_0_newBody = (UA_Byte *) UA_malloc(variablenode_ns_0_i_12169_EnumValueType_1_0_encOffset); +if (!variablenode_ns_0_i_12169_EnumValueType_1_0_newBody) return UA_STATUSCODE_BADOUTOFMEMORY; +memcpy(variablenode_ns_0_i_12169_EnumValueType_1_0_newBody, variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.data, variablenode_ns_0_i_12169_EnumValueType_1_0_encOffset); +UA_Byte *variablenode_ns_0_i_12169_EnumValueType_1_0_oldBody = variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.data; +variablenode_ns_0_i_12169_EnumValueType_1_0->content.encoded.body.data = variablenode_ns_0_i_12169_EnumValueType_1_0_newBody; +UA_free(variablenode_ns_0_i_12169_EnumValueType_1_0_oldBody); + + +struct { + UA_Int64 Value; + UA_LocalizedText DisplayName; + UA_LocalizedText Description; +} variablenode_ns_0_i_12169_EnumValueType_2_0_struct; +UA_ExtensionObject *variablenode_ns_0_i_12169_EnumValueType_2_0 = UA_ExtensionObject_new(); +if (!variablenode_ns_0_i_12169_EnumValueType_2_0) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_12169_EnumValueType_2_0_struct.Value = (UA_Int64) 3; +variablenode_ns_0_i_12169_EnumValueType_2_0_struct.DisplayName = UA_LOCALIZEDTEXT("", "Constraint"); +variablenode_ns_0_i_12169_EnumValueType_2_0_struct.Description = UA_LOCALIZEDTEXT("", "The modelling rule defines a constraint and the BrowseName is not used in an instance of the type."); +variablenode_ns_0_i_12169_EnumValueType_2_0->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; +variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.typeId = UA_NODEID_NUMERIC(0, 8251); +retVal |= UA_ByteString_allocBuffer(&variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body, 65000); +UA_Byte *posvariablenode_ns_0_i_12169_EnumValueType_2_0 = variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.data; +const UA_Byte *endvariablenode_ns_0_i_12169_EnumValueType_2_0 = &variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.data[65000]; +{ +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_2_0_struct.Value, &UA_TYPES[UA_TYPES_INT64], &posvariablenode_ns_0_i_12169_EnumValueType_2_0, &endvariablenode_ns_0_i_12169_EnumValueType_2_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_2_0_struct.DisplayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_12169_EnumValueType_2_0, &endvariablenode_ns_0_i_12169_EnumValueType_2_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_12169_EnumValueType_2_0_struct.Description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_12169_EnumValueType_2_0, &endvariablenode_ns_0_i_12169_EnumValueType_2_0, NULL, NULL); +} +size_t variablenode_ns_0_i_12169_EnumValueType_2_0_encOffset = (uintptr_t)(posvariablenode_ns_0_i_12169_EnumValueType_2_0-variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.data); +variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.length = variablenode_ns_0_i_12169_EnumValueType_2_0_encOffset; +UA_Byte *variablenode_ns_0_i_12169_EnumValueType_2_0_newBody = (UA_Byte *) UA_malloc(variablenode_ns_0_i_12169_EnumValueType_2_0_encOffset); +if (!variablenode_ns_0_i_12169_EnumValueType_2_0_newBody) return UA_STATUSCODE_BADOUTOFMEMORY; +memcpy(variablenode_ns_0_i_12169_EnumValueType_2_0_newBody, variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.data, variablenode_ns_0_i_12169_EnumValueType_2_0_encOffset); +UA_Byte *variablenode_ns_0_i_12169_EnumValueType_2_0_oldBody = variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.data; +variablenode_ns_0_i_12169_EnumValueType_2_0->content.encoded.body.data = variablenode_ns_0_i_12169_EnumValueType_2_0_newBody; +UA_free(variablenode_ns_0_i_12169_EnumValueType_2_0_oldBody); + +UA_ExtensionObject variablenode_ns_0_i_12169_variant_DataContents[3]; +variablenode_ns_0_i_12169_variant_DataContents[0] = *variablenode_ns_0_i_12169_EnumValueType_0_0; +variablenode_ns_0_i_12169_variant_DataContents[1] = *variablenode_ns_0_i_12169_EnumValueType_1_0; +variablenode_ns_0_i_12169_variant_DataContents[2] = *variablenode_ns_0_i_12169_EnumValueType_2_0; +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12169_variant_DataContents, (UA_Int32) 3, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); +attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 12169), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "EnumValues"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); + +UA_ExtensionObject_delete(variablenode_ns_0_i_12169_EnumValueType_0_0); + +UA_ExtensionObject_delete(variablenode_ns_0_i_12169_EnumValueType_1_0); + +UA_ExtensionObject_delete(variablenode_ns_0_i_12169_EnumValueType_2_0); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 12169), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 120), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_55_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 12169) +); +} + +/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11712 */ + +static UA_StatusCode function_ua_namespace0_56_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single TranslateBrowsePathsToNodeIds request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11712), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11712), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_56_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11712) +); +} + +/* MaxMonitoredItemsPerCall - ns=0;i=11574 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single MonitoredItem related request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11574), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11574), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_57_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11574) +); +} + +/* MaxNodesPerNodeManagement - ns=0;i=11573 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single AddNodes, AddReferences, DeleteNodes or DeleteReferences request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11573), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11573), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_58_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11573) +); +} + +/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11572 */ + +static UA_StatusCode function_ua_namespace0_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 = 1; +attr.accessLevel = 1; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single TranslateBrowsePathsToNodeIds request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11572), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11572), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_59_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11572) +); +} + +/* MaxNodesPerRegisterNodes - ns=0;i=11571 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single RegisterNodes request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11571), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11571), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_60_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11571) +); +} + +/* MaxNodesPerBrowse - ns=0;i=11570 */ + +static UA_StatusCode function_ua_namespace0_61_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Browse request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11570), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11570), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11564), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_61_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11570) +); +} + +/* MaxNodesPerRead - ns=0;i=11705 */ + +static UA_StatusCode function_ua_namespace0_62_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single Read request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11705), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11705), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_62_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11705) +); +} + +/* EnumStrings - ns=0;i=7611 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = 1; +attr.arrayDimensionsSize = 1; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 7611), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "EnumStrings"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7611), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 851), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_63_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 7611) +); +} + +/* ServerProfileArray - ns=0;i=2269 */ + +static UA_StatusCode function_ua_namespace0_64_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setArray(&attr.value, NULL, (UA_Int32) 0, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerProfileArray"); +attr.description = UA_LOCALIZEDTEXT("", "A list of profiles supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2269), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerProfileArray"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2269), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_64_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2269) +); +} + +/* MaxQueryContinuationPoints - ns=0;i=2736 */ + +static UA_StatusCode function_ua_namespace0_65_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.dataType = UA_NODEID_NUMERIC(ns[0], 5); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT16]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxQueryContinuationPoints"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of continuation points for Query operations per session."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2736), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxQueryContinuationPoints"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2736), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_65_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2736) +); +} + +/* MaxHistoryContinuationPoints - ns=0;i=2737 */ + +static UA_StatusCode function_ua_namespace0_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.dataType = UA_NODEID_NUMERIC(ns[0], 5); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT16]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxHistoryContinuationPoints"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of continuation points for ReadHistory operations per session."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2737), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxHistoryContinuationPoints"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2737), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_66_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2737) +); +} + +/* MaxNodesPerRegisterNodes - ns=0;i=11711 */ + +static UA_StatusCode function_ua_namespace0_67_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single RegisterNodes request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11711), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11711), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_67_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11711) +); +} + +/* ServiceLevel - ns=0;i=2267 */ + +static UA_StatusCode function_ua_namespace0_68_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.dataType = UA_NODEID_NUMERIC(ns[0], 3); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_BYTE]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServiceLevel"); +attr.description = UA_LOCALIZEDTEXT("", "A value indicating the level of service the server can provide. 255 indicates the best."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2267), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServiceLevel"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2267), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_68_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2267) +); +} + +/* RedundancySupport - ns=0;i=3709 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 851); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]); +attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport"); +attr.description = UA_LOCALIZEDTEXT("", "Indicates what style of redundancy is supported by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 3709), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 3709), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2296), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_69_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3709) +); +} + +/* MaxMonitoredItemsPerCall - ns=0;i=11714 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single MonitoredItem related request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11714), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11714), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_70_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11714) +); +} + +/* MaxNodesPerNodeManagement - ns=0;i=11713 */ + +static UA_StatusCode function_ua_namespace0_71_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement"); +attr.description = UA_LOCALIZEDTEXT("", "The maximum number of operations in a single AddNodes, AddReferences, DeleteNodes or DeleteReferences request."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11713), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11713), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11704), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_71_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11713) +); +} + +/* ModellingRuleType - ns=0;i=77 */ + +static UA_StatusCode function_ua_namespace0_72_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRuleType"); +attr.description = UA_LOCALIZEDTEXT("", "The type for an object that describes how an instance declaration is used when a type is instantiated."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 77), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ModellingRuleType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 77), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_72_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 77) +); +} + +/* NamingRule - ns=0;i=111 */ + +static UA_StatusCode function_ua_namespace0_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; +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; +*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"); +attr.description = UA_LOCALIZEDTEXT("", "Specified the significances of the BrowseName when a type is instantiated."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 111), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "NamingRule"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Int32_delete(variablenode_ns_0_i_111_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 111), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 77), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_73_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 111) +); +} + +/* Mandatory - ns=0;i=78 */ + +static UA_StatusCode function_ua_namespace0_74_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "Mandatory"); +attr.description = UA_LOCALIZEDTEXT("", "Specifies that an instance with the attributes and references of the instance declaration must appear when a type is instantiated."); +attr.writeMask = 0; +attr.userWriteMask = 0; +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], 2035), 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], 2160), 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], 35), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2996), false); +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], 2153), 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], 2151), 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], 2157), 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], 2155), 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], 2159), 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], 2162), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_74_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 78) +); +} + +/* NamingRule - ns=0;i=112 */ + +static UA_StatusCode function_ua_namespace0_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; +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; +*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"); +attr.description = UA_LOCALIZEDTEXT("", "Specified the significances of the BrowseName when a type is instantiated."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 112), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "NamingRule"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Int32_delete(variablenode_ns_0_i_112_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 112), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 78), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_75_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 112) +); +} + +/* Optional - ns=0;i=80 */ + +static UA_StatusCode function_ua_namespace0_76_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.description = UA_LOCALIZEDTEXT("", "Specifies that an instance with the attributes and references of the instance declaration may appear when a type is instantiated."); +attr.writeMask = 0; +attr.userWriteMask = 0; +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), +(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], 35), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2996), 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], 11565), 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], 11574), 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], 11570), false); +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], 11572), 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); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_76_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 80) +); +} + +/* NamingRule - ns=0;i=113 */ + +static UA_StatusCode function_ua_namespace0_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; +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; +*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"); +attr.description = UA_LOCALIZEDTEXT("", "Specified the significances of the BrowseName when a type is instantiated."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 113), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "NamingRule"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Int32_delete(variablenode_ns_0_i_113_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 113), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_77_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 113) +); +} + +/* DataTypeEncodingType - ns=0;i=76 */ + +static UA_StatusCode function_ua_namespace0_78_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeEncodingType"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 76), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataTypeEncodingType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 76), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_78_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 76) +); +} + +/* Default Binary - ns=0;i=8251 */ + +static UA_StatusCode function_ua_namespace0_79_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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +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_QUALIFIEDNAME(ns[0], "Default Binary"), +UA_NODEID_NUMERIC(ns[0], 76), +(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); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_79_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 8251) +); +} + +/* DataTypeSystemType - ns=0;i=75 */ + +static UA_StatusCode function_ua_namespace0_80_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeSystemType"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 75), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataTypeSystemType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 75), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_80_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 75) +); +} + +/* OPC Binary - ns=0;i=93 */ + +static UA_StatusCode function_ua_namespace0_81_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.description = UA_LOCALIZEDTEXT("", "A type system which uses OPC binary schema to describe the encoding of data types."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 93), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "OPC Binary"), +UA_NODEID_NUMERIC(ns[0], 75), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 93), UA_NODEID_NUMERIC(ns[0], 35), UA_EXPANDEDNODEID_NUMERIC(ns[0], 90), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_81_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 93) +); +} + +/* DataTypeDictionaryType - ns=0;i=72 */ + +static UA_StatusCode function_ua_namespace0_82_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = (UA_Int32)-2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDictionaryType"); +attr.description = UA_LOCALIZEDTEXT("", "The type for variable that represents the collection of data type decriptions."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 72), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataTypeDictionaryType"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 72), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 63), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_82_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 72) +); +} + +/* NamespaceUri - ns=0;i=107 */ + +static UA_StatusCode function_ua_namespace0_83_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceUri"); +attr.description = UA_LOCALIZEDTEXT("", "A URI that uniquely identifies the dictionary."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 107), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "NamespaceUri"), +UA_NODEID_NUMERIC(ns[0], 68), +(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], 107), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 72), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_83_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 107) +); +} + +/* DataTypeVersion - ns=0;i=106 */ + +static UA_StatusCode function_ua_namespace0_84_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion"); +attr.description = UA_LOCALIZEDTEXT("", "The version number for the data type dictionary."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 106), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"), +UA_NODEID_NUMERIC(ns[0], 68), +(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], 106), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 72), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_84_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 106) +); +} + +/* Opc.Ua - ns=0;i=7617 */ + +static UA_StatusCode function_ua_namespace0_85_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.dataType = UA_NODEID_NUMERIC(ns[0], 15); +UA_ByteString *variablenode_ns_0_i_7617_variant_DataContents = UA_ByteString_new(); +if (!variablenode_ns_0_i_7617_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY; +*variablenode_ns_0_i_7617_variant_DataContents = UA_BYTESTRING_NULL; +UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7617_variant_DataContents, &UA_TYPES[UA_TYPES_BYTESTRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "Opc.Ua"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 7617), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Opc.Ua"), +UA_NODEID_NUMERIC(ns[0], 72), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_ByteString_delete(variablenode_ns_0_i_7617_variant_DataContents); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7617), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 93), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_85_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 7617) +); +} + +/* ServerStatusDataType - ns=0;i=862 */ + +static UA_StatusCode function_ua_namespace0_86_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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 862), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerStatusDataType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 862), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 22), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_86_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 862) +); +} + +/* DataTypeDescriptionType - ns=0;i=69 */ + +static UA_StatusCode function_ua_namespace0_87_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = (UA_Int32)-2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDescriptionType"); +attr.description = UA_LOCALIZEDTEXT("", "The type for variable that represents the description of a data type encoding."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 69), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataTypeDescriptionType"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 69), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 63), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_87_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 69) +); +} + +/* DictionaryFragment - ns=0;i=105 */ + +static UA_StatusCode function_ua_namespace0_88_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.dataType = UA_NODEID_NUMERIC(ns[0], 15); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_BYTESTRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "DictionaryFragment"); +attr.description = UA_LOCALIZEDTEXT("", "A fragment of a data type dictionary that defines the data type."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 105), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DictionaryFragment"), +UA_NODEID_NUMERIC(ns[0], 68), +(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); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 105), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 69), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_88_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 105) +); +} + +/* DataTypeVersion - ns=0;i=104 */ + +static UA_StatusCode function_ua_namespace0_89_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion"); +attr.description = UA_LOCALIZEDTEXT("", "The version number for the data type description."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 104), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"), +UA_NODEID_NUMERIC(ns[0], 68), +(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], 104), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 69), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_89_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 104) +); +} + +/* Argument - ns=0;i=7650 */ + +static UA_StatusCode function_ua_namespace0_90_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.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; +*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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 7650), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Argument"), +UA_NODEID_NUMERIC(ns[0], 69), +(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], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7617), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_90_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 7650) +); +} + +/* EnumValueType - ns=0;i=7656 */ + +static UA_StatusCode function_ua_namespace0_91_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.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; +*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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 7656), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "EnumValueType"), +UA_NODEID_NUMERIC(ns[0], 69), +(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], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7617), false); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7656), UA_NODEID_NUMERIC(ns[0], 39), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8251), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_91_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 7656) +); +} + +/* ServerDiagnosticsSummaryDataType - ns=0;i=859 */ + +static UA_StatusCode function_ua_namespace0_92_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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 859), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummaryDataType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 859), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 22), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_92_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 859) +); +} + +/* SignedSoftwareCertificate - ns=0;i=344 */ + +static UA_StatusCode function_ua_namespace0_93_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "SignedSoftwareCertificate"); +attr.description = UA_LOCALIZEDTEXT("", "A software certificate with a digital signature."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 344), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SignedSoftwareCertificate"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 344), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 22), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_93_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 344) +); +} + +/* SoftwareCertificates - ns=0;i=3704 */ + +static UA_StatusCode function_ua_namespace0_94_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 344); +UA_Variant_setArray(&attr.value, NULL, (UA_Int32) 0, &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE]); +attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareCertificates"); +attr.description = UA_LOCALIZEDTEXT("", "The software certificates owned by the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 3704), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SoftwareCertificates"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 3704), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2268), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_94_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3704) +); +} + +/* VendorServerInfoType - ns=0;i=2033 */ + +static UA_StatusCode function_ua_namespace0_95_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfoType"); +attr.description = UA_LOCALIZEDTEXT("", "A base type for vendor specific server information."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2033), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "VendorServerInfoType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2033), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_95_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2033) +); +} + +/* VendorServerInfo - ns=0;i=2295 */ + +static UA_StatusCode function_ua_namespace0_96_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.description = UA_LOCALIZEDTEXT("", "Server information provided by the vendor."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2295), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"), +UA_NODEID_NUMERIC(ns[0], 2033), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2295), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_96_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2295) +); +} + +/* VendorServerInfo - ns=0;i=2011 */ + +static UA_StatusCode function_ua_namespace0_97_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.description = UA_LOCALIZEDTEXT("", "Server information provided by the vendor."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2011), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"), +UA_NODEID_NUMERIC(ns[0], 2033), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2011), UA_NODEID_NUMERIC(ns[0], 37), UA_EXPANDEDNODEID_NUMERIC(ns[0], 78), true); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2011), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2004), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_97_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2011) +); +} + +/* ServerStatusType - ns=0;i=2138 */ + +static UA_StatusCode function_ua_namespace0_98_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; +attr.valueRank = (UA_Int32)-2; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 24); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusType"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE, +UA_NODEID_NUMERIC(ns[0], 2138), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerStatusType"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2138), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 63), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_98_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2138) +); +} + +/* ServerStatus - ns=0;i=2256 */ + +static UA_StatusCode function_ua_namespace0_99_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.dataType = UA_NODEID_NUMERIC(ns[0], 862); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatus"); +attr.description = UA_LOCALIZEDTEXT("", "The current status of the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2256), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerStatus"), +UA_NODEID_NUMERIC(ns[0], 2138), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2256), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_99_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2256) +); +} + +/* State - ns=0;i=2259 */ + +static UA_StatusCode function_ua_namespace0_100_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.dataType = UA_NODEID_NUMERIC(ns[0], 852); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_SERVERSTATE]); +attr.displayName = UA_LOCALIZEDTEXT("", "State"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2259), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "State"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2259), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2256), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_100_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2259) +); +} + +/* CurrentTime - ns=0;i=2258 */ + +static UA_StatusCode function_ua_namespace0_101_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.dataType = UA_NODEID_NUMERIC(ns[0], 294); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_DATETIME]); +attr.displayName = UA_LOCALIZEDTEXT("", "CurrentTime"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2258), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CurrentTime"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2258), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2256), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_101_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2258) +); +} + +/* StartTime - ns=0;i=2257 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 294); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_DATETIME]); +attr.displayName = UA_LOCALIZEDTEXT("", "StartTime"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2257), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "StartTime"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2257), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2256), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_102_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2257) +); +} + +/* BuildInfo - ns=0;i=2260 */ + +static UA_StatusCode function_ua_namespace0_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.userAccessLevel = 1; +attr.accessLevel = 1; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 338); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_BUILDINFO]); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2260), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "BuildInfo"), +UA_NODEID_NUMERIC(ns[0], 3051), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2260), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2256), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_103_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2260) +); +} + +/* BuildDate - ns=0;i=2266 */ + +static UA_StatusCode function_ua_namespace0_104_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.dataType = UA_NODEID_NUMERIC(ns[0], 294); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_DATETIME]); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildDate"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2266), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "BuildDate"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2266), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2260), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_104_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2266) +); +} + +/* BuildNumber - ns=0;i=2265 */ + +static UA_StatusCode function_ua_namespace0_105_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "BuildNumber"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2265), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "BuildNumber"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2265), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2260), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_105_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2265) +); +} + +/* SoftwareVersion - ns=0;i=2264 */ + +static UA_StatusCode function_ua_namespace0_106_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareVersion"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2264), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SoftwareVersion"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2264), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2260), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_106_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2264) +); +} + +/* ManufacturerName - ns=0;i=2263 */ + +static UA_StatusCode function_ua_namespace0_107_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "ManufacturerName"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2263), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ManufacturerName"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2263), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2260), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_107_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2263) +); +} + +/* ProductUri - ns=0;i=2262 */ + +static UA_StatusCode function_ua_namespace0_108_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "ProductUri"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2262), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ProductUri"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2262), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2260), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_108_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2262) +); +} + +/* ProductName - ns=0;i=2261 */ + +static UA_StatusCode function_ua_namespace0_109_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.dataType = UA_NODEID_NUMERIC(ns[0], 12); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_STRING]); +attr.displayName = UA_LOCALIZEDTEXT("", "ProductName"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2261), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ProductName"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2261), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2260), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_109_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2261) +); +} + +/* SecondsTillShutdown - ns=0;i=2992 */ + +static UA_StatusCode function_ua_namespace0_110_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SecondsTillShutdown"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2992), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SecondsTillShutdown"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2992), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2256), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_110_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2992) +); +} + +/* ShutdownReason - ns=0;i=2993 */ + +static UA_StatusCode function_ua_namespace0_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; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 21); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); +attr.displayName = UA_LOCALIZEDTEXT("", "ShutdownReason"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2993), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ShutdownReason"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2993), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2256), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_111_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2993) +); +} + +/* Argument - ns=0;i=296 */ + +static UA_StatusCode function_ua_namespace0_112_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "Argument"); +attr.description = UA_LOCALIZEDTEXT("", "An argument for a method."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE, +UA_NODEID_NUMERIC(ns[0], 296), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "Argument"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 296), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 22), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_112_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 296) +); +} + +/* Default Binary - ns=0;i=298 */ + +static UA_StatusCode function_ua_namespace0_113_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.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +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), +(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], 39), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7650), true); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 298), UA_NODEID_NUMERIC(ns[0], 38), UA_EXPANDEDNODEID_NUMERIC(ns[0], 296), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_113_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 298) +); +} + +/* OutputArguments - ns=0;i=11494 */ + +static UA_StatusCode function_ua_namespace0_114_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 296); + +struct { + UA_String Name; + UA_NodeId DataType; + UA_Int32 ValueRank; + UA_Int32 ArrayDimensionsSize; + UA_UInt32 *ArrayDimensions; + UA_LocalizedText Description; +} variablenode_ns_0_i_11494_Argument_0_0_struct; +UA_ExtensionObject *variablenode_ns_0_i_11494_Argument_0_0 = UA_ExtensionObject_new(); +if (!variablenode_ns_0_i_11494_Argument_0_0) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_11494_Argument_0_0_struct.Name = UA_STRING("ServerHandles"); +variablenode_ns_0_i_11494_Argument_0_0_struct.DataType = UA_NODEID_NUMERIC(ns[0], 7); +variablenode_ns_0_i_11494_Argument_0_0_struct.ValueRank = (UA_Int32) 1; +variablenode_ns_0_i_11494_Argument_0_0_struct.ArrayDimensionsSize = 1; +variablenode_ns_0_i_11494_Argument_0_0_struct.ArrayDimensions = (UA_UInt32*) UA_malloc(sizeof(UA_UInt32)); +if (!variablenode_ns_0_i_11494_Argument_0_0_struct.ArrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_11494_Argument_0_0_struct.ArrayDimensions[0] = (UA_UInt32) 0; +variablenode_ns_0_i_11494_Argument_0_0_struct.Description = UA_LOCALIZEDTEXT("", ""); +variablenode_ns_0_i_11494_Argument_0_0->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; +variablenode_ns_0_i_11494_Argument_0_0->content.encoded.typeId = UA_NODEID_NUMERIC(0, 298); +retVal |= UA_ByteString_allocBuffer(&variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body, 65000); +UA_Byte *posvariablenode_ns_0_i_11494_Argument_0_0 = variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.data; +const UA_Byte *endvariablenode_ns_0_i_11494_Argument_0_0 = &variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.data[65000]; +{ +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_0_0_struct.Name, &UA_TYPES[UA_TYPES_STRING], &posvariablenode_ns_0_i_11494_Argument_0_0, &endvariablenode_ns_0_i_11494_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_0_0_struct.DataType, &UA_TYPES[UA_TYPES_NODEID], &posvariablenode_ns_0_i_11494_Argument_0_0, &endvariablenode_ns_0_i_11494_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_0_0_struct.ValueRank, &UA_TYPES[UA_TYPES_INT32], &posvariablenode_ns_0_i_11494_Argument_0_0, &endvariablenode_ns_0_i_11494_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_0_0_struct.ArrayDimensions[0], &UA_TYPES[UA_TYPES_UINT32], &posvariablenode_ns_0_i_11494_Argument_0_0, &endvariablenode_ns_0_i_11494_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_0_0_struct.Description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_11494_Argument_0_0, &endvariablenode_ns_0_i_11494_Argument_0_0, NULL, NULL); +} +size_t variablenode_ns_0_i_11494_Argument_0_0_encOffset = (uintptr_t)(posvariablenode_ns_0_i_11494_Argument_0_0-variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.data); +variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.length = variablenode_ns_0_i_11494_Argument_0_0_encOffset; +UA_Byte *variablenode_ns_0_i_11494_Argument_0_0_newBody = (UA_Byte *) UA_malloc(variablenode_ns_0_i_11494_Argument_0_0_encOffset); +if (!variablenode_ns_0_i_11494_Argument_0_0_newBody) return UA_STATUSCODE_BADOUTOFMEMORY; +memcpy(variablenode_ns_0_i_11494_Argument_0_0_newBody, variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.data, variablenode_ns_0_i_11494_Argument_0_0_encOffset); +UA_Byte *variablenode_ns_0_i_11494_Argument_0_0_oldBody = variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.data; +variablenode_ns_0_i_11494_Argument_0_0->content.encoded.body.data = variablenode_ns_0_i_11494_Argument_0_0_newBody; +UA_free(variablenode_ns_0_i_11494_Argument_0_0_oldBody); + + +struct { + UA_String Name; + UA_NodeId DataType; + UA_Int32 ValueRank; + UA_Int32 ArrayDimensionsSize; + UA_UInt32 *ArrayDimensions; + UA_LocalizedText Description; +} variablenode_ns_0_i_11494_Argument_1_0_struct; +UA_ExtensionObject *variablenode_ns_0_i_11494_Argument_1_0 = UA_ExtensionObject_new(); +if (!variablenode_ns_0_i_11494_Argument_1_0) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_11494_Argument_1_0_struct.Name = UA_STRING("ClientHandles"); +variablenode_ns_0_i_11494_Argument_1_0_struct.DataType = UA_NODEID_NUMERIC(ns[0], 7); +variablenode_ns_0_i_11494_Argument_1_0_struct.ValueRank = (UA_Int32) 1; +variablenode_ns_0_i_11494_Argument_1_0_struct.ArrayDimensionsSize = 1; +variablenode_ns_0_i_11494_Argument_1_0_struct.ArrayDimensions = (UA_UInt32*) UA_malloc(sizeof(UA_UInt32)); +if (!variablenode_ns_0_i_11494_Argument_1_0_struct.ArrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_11494_Argument_1_0_struct.ArrayDimensions[0] = (UA_UInt32) 0; +variablenode_ns_0_i_11494_Argument_1_0_struct.Description = UA_LOCALIZEDTEXT("", ""); +variablenode_ns_0_i_11494_Argument_1_0->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; +variablenode_ns_0_i_11494_Argument_1_0->content.encoded.typeId = UA_NODEID_NUMERIC(0, 298); +retVal |= UA_ByteString_allocBuffer(&variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body, 65000); +UA_Byte *posvariablenode_ns_0_i_11494_Argument_1_0 = variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.data; +const UA_Byte *endvariablenode_ns_0_i_11494_Argument_1_0 = &variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.data[65000]; +{ +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_1_0_struct.Name, &UA_TYPES[UA_TYPES_STRING], &posvariablenode_ns_0_i_11494_Argument_1_0, &endvariablenode_ns_0_i_11494_Argument_1_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_1_0_struct.DataType, &UA_TYPES[UA_TYPES_NODEID], &posvariablenode_ns_0_i_11494_Argument_1_0, &endvariablenode_ns_0_i_11494_Argument_1_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_1_0_struct.ValueRank, &UA_TYPES[UA_TYPES_INT32], &posvariablenode_ns_0_i_11494_Argument_1_0, &endvariablenode_ns_0_i_11494_Argument_1_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_1_0_struct.ArrayDimensions[0], &UA_TYPES[UA_TYPES_UINT32], &posvariablenode_ns_0_i_11494_Argument_1_0, &endvariablenode_ns_0_i_11494_Argument_1_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11494_Argument_1_0_struct.Description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_11494_Argument_1_0, &endvariablenode_ns_0_i_11494_Argument_1_0, NULL, NULL); +} +size_t variablenode_ns_0_i_11494_Argument_1_0_encOffset = (uintptr_t)(posvariablenode_ns_0_i_11494_Argument_1_0-variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.data); +variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.length = variablenode_ns_0_i_11494_Argument_1_0_encOffset; +UA_Byte *variablenode_ns_0_i_11494_Argument_1_0_newBody = (UA_Byte *) UA_malloc(variablenode_ns_0_i_11494_Argument_1_0_encOffset); +if (!variablenode_ns_0_i_11494_Argument_1_0_newBody) return UA_STATUSCODE_BADOUTOFMEMORY; +memcpy(variablenode_ns_0_i_11494_Argument_1_0_newBody, variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.data, variablenode_ns_0_i_11494_Argument_1_0_encOffset); +UA_Byte *variablenode_ns_0_i_11494_Argument_1_0_oldBody = variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.data; +variablenode_ns_0_i_11494_Argument_1_0->content.encoded.body.data = variablenode_ns_0_i_11494_Argument_1_0_newBody; +UA_free(variablenode_ns_0_i_11494_Argument_1_0_oldBody); + +UA_ExtensionObject variablenode_ns_0_i_11494_variant_DataContents[2]; +variablenode_ns_0_i_11494_variant_DataContents[0] = *variablenode_ns_0_i_11494_Argument_0_0; +variablenode_ns_0_i_11494_variant_DataContents[1] = *variablenode_ns_0_i_11494_Argument_1_0; +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11494_variant_DataContents, (UA_Int32) 2, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); +attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11494), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "OutputArguments"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); + +UA_ExtensionObject_delete(variablenode_ns_0_i_11494_Argument_0_0); +UA_free(variablenode_ns_0_i_11494_Argument_0_0_struct.ArrayDimensions); + +UA_ExtensionObject_delete(variablenode_ns_0_i_11494_Argument_1_0); +UA_free(variablenode_ns_0_i_11494_Argument_1_0_struct.ArrayDimensions); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11494), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11492), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_114_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11494) +); +} + +/* InputArguments - ns=0;i=11493 */ + +static UA_StatusCode function_ua_namespace0_115_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; +attr.arrayDimensions = (UA_UInt32 *)UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32]); +if (!attr.arrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +attr.arrayDimensions[0] = 0; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 296); + +struct { + UA_String Name; + UA_NodeId DataType; + UA_Int32 ValueRank; + UA_Int32 ArrayDimensionsSize; + UA_UInt32 *ArrayDimensions; + UA_LocalizedText Description; +} variablenode_ns_0_i_11493_Argument_0_0_struct; +UA_ExtensionObject *variablenode_ns_0_i_11493_Argument_0_0 = UA_ExtensionObject_new(); +if (!variablenode_ns_0_i_11493_Argument_0_0) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_11493_Argument_0_0_struct.Name = UA_STRING("SubscriptionId"); +variablenode_ns_0_i_11493_Argument_0_0_struct.DataType = UA_NODEID_NUMERIC(ns[0], 7); +variablenode_ns_0_i_11493_Argument_0_0_struct.ValueRank = (UA_Int32) -1; +variablenode_ns_0_i_11493_Argument_0_0_struct.ArrayDimensionsSize = 1; +variablenode_ns_0_i_11493_Argument_0_0_struct.ArrayDimensions = (UA_UInt32*) UA_malloc(sizeof(UA_UInt32)); +if (!variablenode_ns_0_i_11493_Argument_0_0_struct.ArrayDimensions) return UA_STATUSCODE_BADOUTOFMEMORY; +variablenode_ns_0_i_11493_Argument_0_0_struct.ArrayDimensions[0] = (UA_UInt32) 0; +variablenode_ns_0_i_11493_Argument_0_0_struct.Description = UA_LOCALIZEDTEXT("", ""); +variablenode_ns_0_i_11493_Argument_0_0->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; +variablenode_ns_0_i_11493_Argument_0_0->content.encoded.typeId = UA_NODEID_NUMERIC(0, 298); +retVal |= UA_ByteString_allocBuffer(&variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body, 65000); +UA_Byte *posvariablenode_ns_0_i_11493_Argument_0_0 = variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.data; +const UA_Byte *endvariablenode_ns_0_i_11493_Argument_0_0 = &variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.data[65000]; +{ +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11493_Argument_0_0_struct.Name, &UA_TYPES[UA_TYPES_STRING], &posvariablenode_ns_0_i_11493_Argument_0_0, &endvariablenode_ns_0_i_11493_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11493_Argument_0_0_struct.DataType, &UA_TYPES[UA_TYPES_NODEID], &posvariablenode_ns_0_i_11493_Argument_0_0, &endvariablenode_ns_0_i_11493_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11493_Argument_0_0_struct.ValueRank, &UA_TYPES[UA_TYPES_INT32], &posvariablenode_ns_0_i_11493_Argument_0_0, &endvariablenode_ns_0_i_11493_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11493_Argument_0_0_struct.ArrayDimensions[0], &UA_TYPES[UA_TYPES_UINT32], &posvariablenode_ns_0_i_11493_Argument_0_0, &endvariablenode_ns_0_i_11493_Argument_0_0, NULL, NULL); +retVal |= UA_encodeBinary(&variablenode_ns_0_i_11493_Argument_0_0_struct.Description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &posvariablenode_ns_0_i_11493_Argument_0_0, &endvariablenode_ns_0_i_11493_Argument_0_0, NULL, NULL); +} +size_t variablenode_ns_0_i_11493_Argument_0_0_encOffset = (uintptr_t)(posvariablenode_ns_0_i_11493_Argument_0_0-variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.data); +variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.length = variablenode_ns_0_i_11493_Argument_0_0_encOffset; +UA_Byte *variablenode_ns_0_i_11493_Argument_0_0_newBody = (UA_Byte *) UA_malloc(variablenode_ns_0_i_11493_Argument_0_0_encOffset); +if (!variablenode_ns_0_i_11493_Argument_0_0_newBody) return UA_STATUSCODE_BADOUTOFMEMORY; +memcpy(variablenode_ns_0_i_11493_Argument_0_0_newBody, variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.data, variablenode_ns_0_i_11493_Argument_0_0_encOffset); +UA_Byte *variablenode_ns_0_i_11493_Argument_0_0_oldBody = variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.data; +variablenode_ns_0_i_11493_Argument_0_0->content.encoded.body.data = variablenode_ns_0_i_11493_Argument_0_0_newBody; +UA_free(variablenode_ns_0_i_11493_Argument_0_0_oldBody); + +UA_ExtensionObject variablenode_ns_0_i_11493_variant_DataContents[1]; +variablenode_ns_0_i_11493_variant_DataContents[0] = *variablenode_ns_0_i_11493_Argument_0_0; +UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11493_variant_DataContents, (UA_Int32) 1, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); +attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 11493), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "InputArguments"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +UA_Array_delete(attr.arrayDimensions, 1, &UA_TYPES[UA_TYPES_UINT32]); + +UA_ExtensionObject_delete(variablenode_ns_0_i_11493_Argument_0_0); +UA_free(variablenode_ns_0_i_11493_Argument_0_0_struct.ArrayDimensions); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11493), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11492), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_115_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 11493) +); +} + +/* Default XML - ns=0;i=3063 */ + +static UA_StatusCode function_ua_namespace0_116_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"); +attr.description = UA_LOCALIZEDTEXT("", "The default XML encoding for a data type."); +attr.writeMask = 0; +attr.userWriteMask = 0; +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_QUALIFIEDNAME(ns[0], "Default XML"), +UA_NODEID_NUMERIC(ns[0], 58), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_116_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3063) +); +} + +/* Default Binary - ns=0;i=3062 */ + +static UA_StatusCode function_ua_namespace0_117_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.description = UA_LOCALIZEDTEXT("", "The default binary encoding for a data type."); +attr.writeMask = 0; +attr.userWriteMask = 0; +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_QUALIFIEDNAME(ns[0], "Default Binary"), +UA_NODEID_NUMERIC(ns[0], 58), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_117_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3062) +); +} + +/* ServerDiagnosticsType - ns=0;i=2020 */ + +static UA_StatusCode function_ua_namespace0_118_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsType"); +attr.description = UA_LOCALIZEDTEXT("", "The diagnostics information for a server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE, +UA_NODEID_NUMERIC(ns[0], 2020), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsType"), +UA_NODEID_NULL, +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2020), UA_NODEID_NUMERIC(ns[0], 45), UA_EXPANDEDNODEID_NUMERIC(ns[0], 58), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_118_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2020) +); +} + +/* ServerDiagnostics - ns=0;i=2274 */ + +static UA_StatusCode function_ua_namespace0_119_begin(UA_Server *server, UA_UInt16* ns) { + +UA_StatusCode retVal = UA_STATUSCODE_GOOD; +UA_ObjectAttributes attr = UA_ObjectAttributes_default; +attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnostics"); +attr.description = UA_LOCALIZEDTEXT("", "Reports diagnostics about the server."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, +UA_NODEID_NUMERIC(ns[0], 2274), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnostics"), +UA_NODEID_NUMERIC(ns[0], 2020), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2274), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2253), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_119_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2274) +); +} + +/* ServerDiagnosticsSummary - ns=0;i=2275 */ + +static UA_StatusCode function_ua_namespace0_120_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.dataType = UA_NODEID_NUMERIC(ns[0], 859); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummary"); +attr.description = UA_LOCALIZEDTEXT("", "A summary of server level diagnostics."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2275), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummary"), +UA_NODEID_NUMERIC(ns[0], 2150), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2275), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2274), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_120_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2275) +); +} + +/* SecurityRejectedRequestsCount - ns=0;i=2287 */ + +static UA_StatusCode function_ua_namespace0_121_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2287), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2287), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_121_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2287) +); +} + +/* CumulatedSubscriptionCount - ns=0;i=2286 */ + +static UA_StatusCode function_ua_namespace0_122_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2286), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2286), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_122_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2286) +); +} + +/* CurrentSubscriptionCount - ns=0;i=2285 */ + +static UA_StatusCode function_ua_namespace0_123_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2285), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2285), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_123_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2285) +); +} + +/* PublishingIntervalCount - ns=0;i=2284 */ + +static UA_StatusCode function_ua_namespace0_124_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2284), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2284), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_124_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2284) +); +} + +/* SessionAbortCount - ns=0;i=2282 */ + +static UA_StatusCode function_ua_namespace0_125_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2282), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2282), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_125_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2282) +); +} + +/* SessionTimeoutCount - ns=0;i=2281 */ + +static UA_StatusCode function_ua_namespace0_126_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2281), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2281), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_126_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2281) +); +} + +/* RejectedSessionCount - ns=0;i=3705 */ + +static UA_StatusCode function_ua_namespace0_127_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 3705), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 3705), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_127_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 3705) +); +} + +/* RejectedRequestsCount - ns=0;i=2288 */ + +static UA_StatusCode function_ua_namespace0_128_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2288), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2288), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_128_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2288) +); +} + +/* ServerViewCount - ns=0;i=2276 */ + +static UA_StatusCode function_ua_namespace0_129_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2276), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "ServerViewCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2276), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_129_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2276) +); +} + +/* CurrentSessionCount - ns=0;i=2277 */ + +static UA_StatusCode function_ua_namespace0_130_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2277), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2277), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_130_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2277) +); +} + +/* CumulatedSessionCount - ns=0;i=2278 */ + +static UA_StatusCode function_ua_namespace0_131_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2278), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2278), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_131_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2278) +); +} + +/* SecurityRejectedSessionCount - ns=0;i=2279 */ + +static UA_StatusCode function_ua_namespace0_132_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.dataType = UA_NODEID_NUMERIC(ns[0], 7); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_UINT32]); +attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount"); +attr.description = UA_LOCALIZEDTEXT("", ""); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2279), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"), +UA_NODEID_NUMERIC(ns[0], 63), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2279), UA_NODEID_NUMERIC(ns[0], 47), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2275), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_132_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2279) +); +} + +/* EnabledFlag - ns=0;i=2294 */ + +static UA_StatusCode function_ua_namespace0_133_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 = 3; +attr.valueRank = -1; +attr.dataType = UA_NODEID_NUMERIC(ns[0], 1); +UA_Variant_setScalar(&attr.value, NULL, &UA_TYPES[UA_TYPES_BOOLEAN]); +attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag"); +attr.description = UA_LOCALIZEDTEXT("", "If TRUE the diagnostics collection is enabled."); +attr.writeMask = 0; +attr.userWriteMask = 0; +retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE, +UA_NODEID_NUMERIC(ns[0], 2294), +UA_NODEID_NUMERIC(ns[0], 0), +UA_NODEID_NUMERIC(ns[0], 0), +UA_QUALIFIEDNAME(ns[0], "EnabledFlag"), +UA_NODEID_NUMERIC(ns[0], 68), +(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL); +retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 2294), UA_NODEID_NUMERIC(ns[0], 46), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2274), false); +return retVal; +} + +static UA_StatusCode function_ua_namespace0_133_finish(UA_Server *server, UA_UInt16* ns) { + +return UA_Server_addNode_finish(server, +UA_NODEID_NUMERIC(ns[0], 2294) +); +} + +UA_StatusCode ua_namespace0(UA_Server *server) { +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/"); +retVal |= function_ua_namespace0_0_begin(server, ns); +retVal |= function_ua_namespace0_1_begin(server, ns); +retVal |= function_ua_namespace0_2_begin(server, ns); +retVal |= function_ua_namespace0_3_begin(server, ns); +retVal |= function_ua_namespace0_4_begin(server, ns); +retVal |= function_ua_namespace0_5_begin(server, ns); +retVal |= function_ua_namespace0_6_begin(server, ns); +retVal |= function_ua_namespace0_7_begin(server, ns); +retVal |= function_ua_namespace0_8_begin(server, ns); +retVal |= function_ua_namespace0_9_begin(server, ns); +retVal |= function_ua_namespace0_10_begin(server, ns); +retVal |= function_ua_namespace0_11_begin(server, ns); +retVal |= function_ua_namespace0_12_begin(server, ns); +retVal |= function_ua_namespace0_13_begin(server, ns); +retVal |= function_ua_namespace0_14_begin(server, ns); +retVal |= function_ua_namespace0_15_begin(server, ns); +retVal |= function_ua_namespace0_16_begin(server, ns); +retVal |= function_ua_namespace0_17_begin(server, ns); +retVal |= function_ua_namespace0_18_begin(server, ns); +retVal |= function_ua_namespace0_19_begin(server, ns); +retVal |= function_ua_namespace0_20_begin(server, ns); +retVal |= function_ua_namespace0_21_begin(server, ns); +retVal |= function_ua_namespace0_22_begin(server, ns); +retVal |= function_ua_namespace0_23_begin(server, ns); +retVal |= function_ua_namespace0_24_begin(server, ns); +retVal |= function_ua_namespace0_25_begin(server, ns); +retVal |= function_ua_namespace0_26_begin(server, ns); +retVal |= function_ua_namespace0_27_begin(server, ns); +retVal |= function_ua_namespace0_28_begin(server, ns); +retVal |= function_ua_namespace0_29_begin(server, ns); +retVal |= function_ua_namespace0_30_begin(server, ns); +retVal |= function_ua_namespace0_31_begin(server, ns); +retVal |= function_ua_namespace0_32_begin(server, ns); +retVal |= function_ua_namespace0_33_begin(server, ns); +retVal |= function_ua_namespace0_34_begin(server, ns); +retVal |= function_ua_namespace0_35_begin(server, ns); +retVal |= function_ua_namespace0_36_begin(server, ns); +retVal |= function_ua_namespace0_37_begin(server, ns); +retVal |= function_ua_namespace0_38_begin(server, ns); +retVal |= function_ua_namespace0_39_begin(server, ns); +retVal |= function_ua_namespace0_40_begin(server, ns); +retVal |= function_ua_namespace0_41_begin(server, ns); +retVal |= function_ua_namespace0_42_begin(server, ns); +retVal |= function_ua_namespace0_43_begin(server, ns); +retVal |= function_ua_namespace0_44_begin(server, ns); +retVal |= function_ua_namespace0_45_begin(server, ns); +retVal |= function_ua_namespace0_46_begin(server, ns); +retVal |= function_ua_namespace0_47_begin(server, ns); +retVal |= function_ua_namespace0_48_begin(server, ns); +retVal |= function_ua_namespace0_49_begin(server, ns); +retVal |= function_ua_namespace0_50_begin(server, ns); +retVal |= function_ua_namespace0_51_begin(server, ns); +retVal |= function_ua_namespace0_52_begin(server, ns); +retVal |= function_ua_namespace0_53_begin(server, ns); +retVal |= function_ua_namespace0_54_begin(server, ns); +retVal |= function_ua_namespace0_55_begin(server, ns); +retVal |= function_ua_namespace0_56_begin(server, ns); +retVal |= function_ua_namespace0_57_begin(server, ns); +retVal |= function_ua_namespace0_58_begin(server, ns); +retVal |= function_ua_namespace0_59_begin(server, ns); +retVal |= function_ua_namespace0_60_begin(server, ns); +retVal |= function_ua_namespace0_61_begin(server, ns); +retVal |= function_ua_namespace0_62_begin(server, ns); +retVal |= function_ua_namespace0_63_begin(server, ns); +retVal |= function_ua_namespace0_64_begin(server, ns); +retVal |= function_ua_namespace0_65_begin(server, ns); +retVal |= function_ua_namespace0_66_begin(server, ns); +retVal |= function_ua_namespace0_67_begin(server, ns); +retVal |= function_ua_namespace0_68_begin(server, ns); +retVal |= function_ua_namespace0_69_begin(server, ns); +retVal |= function_ua_namespace0_70_begin(server, ns); +retVal |= function_ua_namespace0_71_begin(server, ns); +retVal |= function_ua_namespace0_72_begin(server, ns); +retVal |= function_ua_namespace0_73_begin(server, ns); +retVal |= function_ua_namespace0_74_begin(server, ns); +retVal |= function_ua_namespace0_75_begin(server, ns); +retVal |= function_ua_namespace0_76_begin(server, ns); +retVal |= function_ua_namespace0_77_begin(server, ns); +retVal |= function_ua_namespace0_78_begin(server, ns); +retVal |= function_ua_namespace0_79_begin(server, ns); +retVal |= function_ua_namespace0_80_begin(server, ns); +retVal |= function_ua_namespace0_81_begin(server, ns); +retVal |= function_ua_namespace0_82_begin(server, ns); +retVal |= function_ua_namespace0_83_begin(server, ns); +retVal |= function_ua_namespace0_84_begin(server, ns); +retVal |= function_ua_namespace0_85_begin(server, ns); +retVal |= function_ua_namespace0_86_begin(server, ns); +retVal |= function_ua_namespace0_87_begin(server, ns); +retVal |= function_ua_namespace0_88_begin(server, ns); +retVal |= function_ua_namespace0_89_begin(server, ns); +retVal |= function_ua_namespace0_90_begin(server, ns); +retVal |= function_ua_namespace0_91_begin(server, ns); +retVal |= function_ua_namespace0_92_begin(server, ns); +retVal |= function_ua_namespace0_93_begin(server, ns); +retVal |= function_ua_namespace0_94_begin(server, ns); +retVal |= function_ua_namespace0_95_begin(server, ns); +retVal |= function_ua_namespace0_96_begin(server, ns); +retVal |= function_ua_namespace0_97_begin(server, ns); +retVal |= function_ua_namespace0_98_begin(server, ns); +retVal |= function_ua_namespace0_99_begin(server, ns); +retVal |= function_ua_namespace0_100_begin(server, ns); +retVal |= function_ua_namespace0_101_begin(server, ns); +retVal |= function_ua_namespace0_102_begin(server, ns); +retVal |= function_ua_namespace0_103_begin(server, ns); +retVal |= function_ua_namespace0_104_begin(server, ns); +retVal |= function_ua_namespace0_105_begin(server, ns); +retVal |= function_ua_namespace0_106_begin(server, ns); +retVal |= function_ua_namespace0_107_begin(server, ns); +retVal |= function_ua_namespace0_108_begin(server, ns); +retVal |= function_ua_namespace0_109_begin(server, ns); +retVal |= function_ua_namespace0_110_begin(server, ns); +retVal |= function_ua_namespace0_111_begin(server, ns); +retVal |= function_ua_namespace0_112_begin(server, ns); +retVal |= function_ua_namespace0_113_begin(server, ns); +retVal |= function_ua_namespace0_114_begin(server, ns); +retVal |= function_ua_namespace0_115_begin(server, ns); +retVal |= function_ua_namespace0_116_begin(server, ns); +retVal |= function_ua_namespace0_117_begin(server, ns); +retVal |= function_ua_namespace0_118_begin(server, ns); +retVal |= function_ua_namespace0_119_begin(server, ns); +retVal |= function_ua_namespace0_120_begin(server, ns); +retVal |= function_ua_namespace0_121_begin(server, ns); +retVal |= function_ua_namespace0_122_begin(server, ns); +retVal |= function_ua_namespace0_123_begin(server, ns); +retVal |= function_ua_namespace0_124_begin(server, ns); +retVal |= function_ua_namespace0_125_begin(server, ns); +retVal |= function_ua_namespace0_126_begin(server, ns); +retVal |= function_ua_namespace0_127_begin(server, ns); +retVal |= function_ua_namespace0_128_begin(server, ns); +retVal |= function_ua_namespace0_129_begin(server, ns); +retVal |= function_ua_namespace0_130_begin(server, ns); +retVal |= function_ua_namespace0_131_begin(server, ns); +retVal |= function_ua_namespace0_132_begin(server, ns); +retVal |= function_ua_namespace0_133_begin(server, ns); +retVal |= function_ua_namespace0_133_finish(server, ns); +retVal |= function_ua_namespace0_132_finish(server, ns); +retVal |= function_ua_namespace0_131_finish(server, ns); +retVal |= function_ua_namespace0_130_finish(server, ns); +retVal |= function_ua_namespace0_129_finish(server, ns); +retVal |= function_ua_namespace0_128_finish(server, ns); +retVal |= function_ua_namespace0_127_finish(server, ns); +retVal |= function_ua_namespace0_126_finish(server, ns); +retVal |= function_ua_namespace0_125_finish(server, ns); +retVal |= function_ua_namespace0_124_finish(server, ns); +retVal |= function_ua_namespace0_123_finish(server, ns); +retVal |= function_ua_namespace0_122_finish(server, ns); +retVal |= function_ua_namespace0_121_finish(server, ns); +retVal |= function_ua_namespace0_120_finish(server, ns); +retVal |= function_ua_namespace0_119_finish(server, ns); +retVal |= function_ua_namespace0_118_finish(server, ns); +retVal |= function_ua_namespace0_117_finish(server, ns); +retVal |= function_ua_namespace0_116_finish(server, ns); +retVal |= function_ua_namespace0_115_finish(server, ns); +retVal |= function_ua_namespace0_114_finish(server, ns); +retVal |= function_ua_namespace0_113_finish(server, ns); +retVal |= function_ua_namespace0_112_finish(server, ns); +retVal |= function_ua_namespace0_111_finish(server, ns); +retVal |= function_ua_namespace0_110_finish(server, ns); +retVal |= function_ua_namespace0_109_finish(server, ns); +retVal |= function_ua_namespace0_108_finish(server, ns); +retVal |= function_ua_namespace0_107_finish(server, ns); +retVal |= function_ua_namespace0_106_finish(server, ns); +retVal |= function_ua_namespace0_105_finish(server, ns); +retVal |= function_ua_namespace0_104_finish(server, ns); +retVal |= function_ua_namespace0_103_finish(server, ns); +retVal |= function_ua_namespace0_102_finish(server, ns); +retVal |= function_ua_namespace0_101_finish(server, ns); +retVal |= function_ua_namespace0_100_finish(server, ns); +retVal |= function_ua_namespace0_99_finish(server, ns); +retVal |= function_ua_namespace0_98_finish(server, ns); +retVal |= function_ua_namespace0_97_finish(server, ns); +retVal |= function_ua_namespace0_96_finish(server, ns); +retVal |= function_ua_namespace0_95_finish(server, ns); +retVal |= function_ua_namespace0_94_finish(server, ns); +retVal |= function_ua_namespace0_93_finish(server, ns); +retVal |= function_ua_namespace0_92_finish(server, ns); +retVal |= function_ua_namespace0_91_finish(server, ns); +retVal |= function_ua_namespace0_90_finish(server, ns); +retVal |= function_ua_namespace0_89_finish(server, ns); +retVal |= function_ua_namespace0_88_finish(server, ns); +retVal |= function_ua_namespace0_87_finish(server, ns); +retVal |= function_ua_namespace0_86_finish(server, ns); +retVal |= function_ua_namespace0_85_finish(server, ns); +retVal |= function_ua_namespace0_84_finish(server, ns); +retVal |= function_ua_namespace0_83_finish(server, ns); +retVal |= function_ua_namespace0_82_finish(server, ns); +retVal |= function_ua_namespace0_81_finish(server, ns); +retVal |= function_ua_namespace0_80_finish(server, ns); +retVal |= function_ua_namespace0_79_finish(server, ns); +retVal |= function_ua_namespace0_78_finish(server, ns); +retVal |= function_ua_namespace0_77_finish(server, ns); +retVal |= function_ua_namespace0_76_finish(server, ns); +retVal |= function_ua_namespace0_75_finish(server, ns); +retVal |= function_ua_namespace0_74_finish(server, ns); +retVal |= function_ua_namespace0_73_finish(server, ns); +retVal |= function_ua_namespace0_72_finish(server, ns); +retVal |= function_ua_namespace0_71_finish(server, ns); +retVal |= function_ua_namespace0_70_finish(server, ns); +retVal |= function_ua_namespace0_69_finish(server, ns); +retVal |= function_ua_namespace0_68_finish(server, ns); +retVal |= function_ua_namespace0_67_finish(server, ns); +retVal |= function_ua_namespace0_66_finish(server, ns); +retVal |= function_ua_namespace0_65_finish(server, ns); +retVal |= function_ua_namespace0_64_finish(server, ns); +retVal |= function_ua_namespace0_63_finish(server, ns); +retVal |= function_ua_namespace0_62_finish(server, ns); +retVal |= function_ua_namespace0_61_finish(server, ns); +retVal |= function_ua_namespace0_60_finish(server, ns); +retVal |= function_ua_namespace0_59_finish(server, ns); +retVal |= function_ua_namespace0_58_finish(server, ns); +retVal |= function_ua_namespace0_57_finish(server, ns); +retVal |= function_ua_namespace0_56_finish(server, ns); +retVal |= function_ua_namespace0_55_finish(server, ns); +retVal |= function_ua_namespace0_54_finish(server, ns); +retVal |= function_ua_namespace0_53_finish(server, ns); +retVal |= function_ua_namespace0_52_finish(server, ns); +retVal |= function_ua_namespace0_51_finish(server, ns); +retVal |= function_ua_namespace0_50_finish(server, ns); +retVal |= function_ua_namespace0_49_finish(server, ns); +retVal |= function_ua_namespace0_48_finish(server, ns); +retVal |= function_ua_namespace0_47_finish(server, ns); +retVal |= function_ua_namespace0_46_finish(server, ns); +retVal |= function_ua_namespace0_45_finish(server, ns); +retVal |= function_ua_namespace0_44_finish(server, ns); +retVal |= function_ua_namespace0_43_finish(server, ns); +retVal |= function_ua_namespace0_42_finish(server, ns); +retVal |= function_ua_namespace0_41_finish(server, ns); +retVal |= function_ua_namespace0_40_finish(server, ns); +retVal |= function_ua_namespace0_39_finish(server, ns); +retVal |= function_ua_namespace0_38_finish(server, ns); +retVal |= function_ua_namespace0_37_finish(server, ns); +retVal |= function_ua_namespace0_36_finish(server, ns); +retVal |= function_ua_namespace0_35_finish(server, ns); +retVal |= function_ua_namespace0_34_finish(server, ns); +retVal |= function_ua_namespace0_33_finish(server, ns); +retVal |= function_ua_namespace0_32_finish(server, ns); +retVal |= function_ua_namespace0_31_finish(server, ns); +retVal |= function_ua_namespace0_30_finish(server, ns); +retVal |= function_ua_namespace0_29_finish(server, ns); +retVal |= function_ua_namespace0_28_finish(server, ns); +retVal |= function_ua_namespace0_27_finish(server, ns); +retVal |= function_ua_namespace0_26_finish(server, ns); +retVal |= function_ua_namespace0_25_finish(server, ns); +retVal |= function_ua_namespace0_24_finish(server, ns); +retVal |= function_ua_namespace0_23_finish(server, ns); +retVal |= function_ua_namespace0_22_finish(server, ns); +retVal |= function_ua_namespace0_21_finish(server, ns); +retVal |= function_ua_namespace0_20_finish(server, ns); +retVal |= function_ua_namespace0_19_finish(server, ns); +retVal |= function_ua_namespace0_18_finish(server, ns); +retVal |= function_ua_namespace0_17_finish(server, ns); +retVal |= function_ua_namespace0_16_finish(server, ns); +retVal |= function_ua_namespace0_15_finish(server, ns); +retVal |= function_ua_namespace0_14_finish(server, ns); +retVal |= function_ua_namespace0_13_finish(server, ns); +retVal |= function_ua_namespace0_12_finish(server, ns); +retVal |= function_ua_namespace0_11_finish(server, ns); +retVal |= function_ua_namespace0_10_finish(server, ns); +retVal |= function_ua_namespace0_9_finish(server, ns); +retVal |= function_ua_namespace0_8_finish(server, ns); +retVal |= function_ua_namespace0_7_finish(server, ns); +retVal |= function_ua_namespace0_6_finish(server, ns); +retVal |= function_ua_namespace0_5_finish(server, ns); +retVal |= function_ua_namespace0_4_finish(server, ns); +retVal |= function_ua_namespace0_3_finish(server, ns); +retVal |= function_ua_namespace0_2_finish(server, ns); +retVal |= function_ua_namespace0_1_finish(server, ns); +retVal |= function_ua_namespace0_0_finish(server, ns); +return retVal; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2016 (c) Sten Grüner + * Copyright 2014-2015, 2017 (c) Florian Palm + * Copyright 2015-2016 (c) Chris Iatrou + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2016 (c) Joakim L. Gilje + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) TorbenD + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +// store the authentication token and session ID so we can help fuzzing by setting +// these values in the next request automatically +UA_NodeId unsafe_fuzz_authenticationToken = { + 0, UA_NODEIDTYPE_NUMERIC, {0} +}; +#endif + +#ifdef UA_DEBUG_DUMP_PKGS_FILE +void UA_debug_dumpCompleteChunk(UA_Server *const server, UA_Connection *const connection, UA_ByteString *messageBuffer); +#endif + +/********************/ +/* Helper Functions */ +/********************/ + + /* This is not an ERR message, the connection is not closed afterwards */ +static UA_StatusCode +sendServiceFault(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); + if(retval != UA_STATUSCODE_GOOD) + return retval; + UA_STACKARRAY(UA_Byte, response, responseType->memSize); + UA_init(response, responseType); + UA_ResponseHeader *responseHeader = (UA_ResponseHeader*)response; + responseHeader->requestHandle = requestHeader.requestHandle; + responseHeader->timestamp = UA_DateTime_now(); + responseHeader->serviceResult = error; + + // Send error message. Message type is MSG and not ERR, since we are on a securechannel! + retval = UA_SecureChannel_sendSymmetricMessage(channel, requestId, UA_MESSAGETYPE_MSG, + response, responseType); + + UA_RequestHeader_deleteMembers(&requestHeader); + UA_LOG_DEBUG(channel->securityPolicy->logger, UA_LOGCATEGORY_SERVER, + "Sent ServiceFault with error code %s", UA_StatusCode_name(error)); + return retval; +} + +typedef enum { + UA_SERVICETYPE_NORMAL, + UA_SERVICETYPE_INSITU, + UA_SERVICETYPE_CUSTOM +} UA_ServiceType; + +static void +getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, + const UA_DataType **responseType, UA_Service *service, + UA_InSituService *serviceInsitu, + UA_Boolean *requiresSession, UA_ServiceType *serviceType) { + switch(requestTypeId) { + case UA_NS0ID_GETENDPOINTSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_GetEndpoints; + *requestType = &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]; + *requiresSession = false; + break; + case UA_NS0ID_FINDSERVERSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_FindServers; + *requestType = &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]; + *requiresSession = false; + break; +#ifdef UA_ENABLE_DISCOVERY +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + case UA_NS0ID_FINDSERVERSONNETWORKREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_FindServersOnNetwork; + *requestType = &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]; + *requiresSession = false; + break; +# endif + case UA_NS0ID_REGISTERSERVERREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_RegisterServer; + *requestType = &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE]; + *requiresSession = false; + break; + case UA_NS0ID_REGISTERSERVER2REQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_RegisterServer2; + *requestType = &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST]; + *responseType = &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE]; + *requiresSession = false; + break; +#endif + case UA_NS0ID_CREATESESSIONREQUEST_ENCODING_DEFAULTBINARY: + *service = NULL; //(UA_Service)Service_CreateSession; + *requestType = &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]; + *requiresSession = false; + *serviceType = UA_SERVICETYPE_CUSTOM; + break; + case UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTBINARY: + *service = NULL; //(UA_Service)Service_ActivateSession; + *requestType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]; + *serviceType = UA_SERVICETYPE_CUSTOM; + break; + case UA_NS0ID_CLOSESESSIONREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_CloseSession; + *requestType = &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]; + break; + case UA_NS0ID_READREQUEST_ENCODING_DEFAULTBINARY: + *service = NULL; + *serviceInsitu = (UA_InSituService)Service_Read; + *requestType = &UA_TYPES[UA_TYPES_READREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_READRESPONSE]; + *serviceType = UA_SERVICETYPE_INSITU; + break; + case UA_NS0ID_WRITEREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_Write; + *requestType = &UA_TYPES[UA_TYPES_WRITEREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_WRITERESPONSE]; + break; + case UA_NS0ID_BROWSEREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_Browse; + *requestType = &UA_TYPES[UA_TYPES_BROWSEREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_BROWSERESPONSE]; + break; + case UA_NS0ID_BROWSENEXTREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_BrowseNext; + *requestType = &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]; + break; + case UA_NS0ID_REGISTERNODESREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_RegisterNodes; + *requestType = &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]; + break; + case UA_NS0ID_UNREGISTERNODESREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_UnregisterNodes; + *requestType = &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]; + break; + case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_TranslateBrowsePathsToNodeIds; + *requestType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]; + break; + +#ifdef UA_ENABLE_SUBSCRIPTIONS + case UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_CreateSubscription; + *requestType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]; + break; + case UA_NS0ID_PUBLISHREQUEST_ENCODING_DEFAULTBINARY: + *requestType = &UA_TYPES[UA_TYPES_PUBLISHREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]; + break; + case UA_NS0ID_REPUBLISHREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_Republish; + *requestType = &UA_TYPES[UA_TYPES_REPUBLISHREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE]; + break; + case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_ModifySubscription; + *requestType = &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]; + break; + case UA_NS0ID_SETPUBLISHINGMODEREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_SetPublishingMode; + *requestType = &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]; + break; + case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_DeleteSubscriptions; + *requestType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]; + break; + case UA_NS0ID_CREATEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_CreateMonitoredItems; + *requestType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]; + break; + case UA_NS0ID_DELETEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_DeleteMonitoredItems; + *requestType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]; + break; + case UA_NS0ID_MODIFYMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_ModifyMonitoredItems; + *requestType = &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]; + break; + case UA_NS0ID_SETMONITORINGMODEREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_SetMonitoringMode; + *requestType = &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]; + break; +#endif + +#ifdef UA_ENABLE_METHODCALLS + case UA_NS0ID_CALLREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_Call; + *requestType = &UA_TYPES[UA_TYPES_CALLREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_CALLRESPONSE]; + break; +#endif + +#ifdef UA_ENABLE_NODEMANAGEMENT + case UA_NS0ID_ADDNODESREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_AddNodes; + *requestType = &UA_TYPES[UA_TYPES_ADDNODESREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]; + break; + case UA_NS0ID_ADDREFERENCESREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_AddReferences; + *requestType = &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]; + break; + case UA_NS0ID_DELETENODESREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_DeleteNodes; + *requestType = &UA_TYPES[UA_TYPES_DELETENODESREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]; + break; + case UA_NS0ID_DELETEREFERENCESREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_DeleteReferences; + *requestType = &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]; + break; +#endif + + default: + break; + } +} + +/*************************/ +/* Process Message Types */ +/*************************/ + +/* HEL -> Open up the connection */ +static UA_StatusCode +processHEL(UA_Server *server, UA_Connection *connection, + const UA_ByteString *msg, size_t *offset) { + UA_TcpHelloMessage helloMessage; + UA_StatusCode retval = UA_TcpHelloMessage_decodeBinary(msg, offset, &helloMessage); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Parameterize the connection */ + connection->remoteConf.maxChunkCount = helloMessage.maxChunkCount; /* zero -> unlimited */ + connection->remoteConf.maxMessageSize = helloMessage.maxMessageSize; /* zero -> unlimited */ + connection->remoteConf.protocolVersion = helloMessage.protocolVersion; + connection->remoteConf.recvBufferSize = helloMessage.receiveBufferSize; + if(connection->localConf.sendBufferSize > helloMessage.receiveBufferSize) + connection->localConf.sendBufferSize = helloMessage.receiveBufferSize; + connection->remoteConf.sendBufferSize = helloMessage.sendBufferSize; + if(connection->localConf.recvBufferSize > helloMessage.sendBufferSize) + connection->localConf.recvBufferSize = helloMessage.sendBufferSize; + UA_String_deleteMembers(&helloMessage.endpointUrl); + + if(connection->remoteConf.recvBufferSize == 0) { + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Remote end indicated a receive buffer size of 0. " + "Not able to send any messages.", + connection->sockfd); + return UA_STATUSCODE_BADINTERNALERROR; + } + + connection->state = UA_CONNECTION_ESTABLISHED; + + /* Build acknowledge response */ + UA_TcpAcknowledgeMessage ackMessage; + ackMessage.protocolVersion = connection->localConf.protocolVersion; + ackMessage.receiveBufferSize = connection->localConf.recvBufferSize; + ackMessage.sendBufferSize = connection->localConf.sendBufferSize; + ackMessage.maxMessageSize = connection->localConf.maxMessageSize; + ackMessage.maxChunkCount = connection->localConf.maxChunkCount; + UA_TcpMessageHeader ackHeader; + ackHeader.messageTypeAndChunkType = UA_MESSAGETYPE_ACK + UA_CHUNKTYPE_FINAL; + ackHeader.messageSize = 8 + 20; /* ackHeader + ackMessage */ + + /* Get the send buffer from the network layer */ + UA_ByteString ack_msg; + UA_ByteString_init(&ack_msg); + retval = connection->getSendBuffer(connection, connection->localConf.sendBufferSize, + &ack_msg); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* 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); + if(retval != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(connection, &ack_msg); + return retval; + } + + retval = UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &bufPos, &bufEnd); + if(retval != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(connection, &ack_msg); + return retval; + } + ack_msg.length = ackHeader.messageSize; + return connection->send(connection, &ack_msg); +} + +/* OPN -> Open up/renew the securechannel */ +static UA_StatusCode +processOPN(UA_Server *server, UA_SecureChannel *channel, + const UA_UInt32 requestId, const UA_ByteString *msg) { + /* Decode the request */ + size_t offset = 0; + UA_NodeId requestType; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_OpenSecureChannelRequest openSecureChannelRequest; + retval |= UA_NodeId_decodeBinary(msg, &offset, &requestType); + retval |= UA_OpenSecureChannelRequest_decodeBinary(msg, &offset, &openSecureChannelRequest); + + /* Error occurred */ + if(retval != UA_STATUSCODE_GOOD || + requestType.identifier.numeric != UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId) { + UA_NodeId_deleteMembers(&requestType); + UA_OpenSecureChannelRequest_deleteMembers(&openSecureChannelRequest); + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Could not decode the OPN message. Closing the connection."); + UA_SecureChannelManager_close(&server->secureChannelManager, channel->securityToken.channelId); + return retval; + } + UA_NodeId_deleteMembers(&requestType); + + /* Call the service */ + UA_OpenSecureChannelResponse openScResponse; + UA_OpenSecureChannelResponse_init(&openScResponse); + Service_OpenSecureChannel(server, channel, &openSecureChannelRequest, &openScResponse); + UA_OpenSecureChannelRequest_deleteMembers(&openSecureChannelRequest); + if(openScResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Could not open a SecureChannel. " + "Closing the connection."); + UA_SecureChannelManager_close(&server->secureChannelManager, + channel->securityToken.channelId); + return openScResponse.responseHeader.serviceResult; + } + + /* Send the response */ + retval = UA_SecureChannel_sendAsymmetricOPNMessage(channel, requestId, &openScResponse, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]); + UA_OpenSecureChannelResponse_deleteMembers(&openScResponse); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Could not send the OPN answer with error code %s", + UA_StatusCode_name(retval)); + UA_SecureChannelManager_close(&server->secureChannelManager, + channel->securityToken.channelId); + } + return retval; +} + +static UA_StatusCode +processMSG(UA_Server *server, UA_SecureChannel *channel, + UA_UInt32 requestId, const UA_ByteString *msg) { + /* At 0, the nodeid starts... */ + size_t offset = 0; + + /* Decode the nodeid */ + UA_NodeId requestTypeId; + UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestTypeId); + if(retval != UA_STATUSCODE_GOOD) + return retval; + if(requestTypeId.namespaceIndex != 0 || + requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC) + UA_NodeId_deleteMembers(&requestTypeId); /* leads to badserviceunsupported */ + + /* Store the start-position of the request */ + size_t requestPos = offset; + + /* Get the service pointers */ + UA_Service service = NULL; + UA_InSituService serviceInsitu = NULL; + const UA_DataType *requestType = NULL; + const UA_DataType *responseType = NULL; + UA_Boolean sessionRequired = true; + UA_ServiceType serviceType = UA_SERVICETYPE_NORMAL; + getServicePointers(requestTypeId.identifier.numeric, &requestType, + &responseType, &service, &serviceInsitu, &sessionRequired, &serviceType); + if(!requestType) { + if(requestTypeId.identifier.numeric == 787) { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Client requested a subscription, " \ + "but those are not enabled in the build"); + } else { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Unknown request with type identifier %i", + requestTypeId.identifier.numeric); + } + return sendServiceFault(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], + requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); + } + UA_assert(responseType); + + /* Decode the request */ + UA_STACKARRAY(UA_Byte, request, requestType->memSize); + UA_RequestHeader *requestHeader = (UA_RequestHeader*)request; + retval = UA_decodeBinary(msg, &offset, request, requestType, + server->config.customDataTypesSize, + server->config.customDataTypes); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, + "Could not decode the request"); + return sendServiceFault(channel, msg, requestPos, responseType, requestId, retval); + } + + /* Prepare the respone */ + UA_STACKARRAY(UA_Byte, responseBuf, responseType->memSize); + void *response = (void*)(uintptr_t)&responseBuf[0]; /* Get around aliasing rules */ + UA_init(response, responseType); + UA_Session *session = NULL; /* must be initialized before goto send_response */ + + /* CreateSession doesn't need a session */ + if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) { + Service_CreateSession(server, channel, + (const UA_CreateSessionRequest *)request, + (UA_CreateSessionResponse *)response); + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // store the authentication token and session ID so we can help fuzzing by setting + // these values in the next request automatically + UA_CreateSessionResponse *res = (UA_CreateSessionResponse *)response; + UA_NodeId_copy(&res->authenticationToken, &unsafe_fuzz_authenticationToken); + #endif + goto send_response; + } + + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // set the authenticationToken from the create session request to help fuzzing cover more lines + UA_NodeId_deleteMembers(&requestHeader->authenticationToken); + if(!UA_NodeId_isNull(&unsafe_fuzz_authenticationToken)) + UA_NodeId_copy(&unsafe_fuzz_authenticationToken, &requestHeader->authenticationToken); + #endif + + /* Find the matching session */ + session = (UA_Session*)UA_SecureChannel_getSession(channel, &requestHeader->authenticationToken); + if(!session && !UA_NodeId_isNull(&requestHeader->authenticationToken)) + session = UA_SessionManager_getSessionByToken(&server->sessionManager, + &requestHeader->authenticationToken); + + if(requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]) { + if(!session) { + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, + "Trying to activate a session that is " \ + "not known in the server"); + UA_deleteMembers(request, requestType); + return sendServiceFault(channel, msg, requestPos, responseType, + requestId, UA_STATUSCODE_BADSESSIONIDINVALID); + } + Service_ActivateSession(server, channel, session, + (const UA_ActivateSessionRequest*)request, + (UA_ActivateSessionResponse*)response); + goto send_response; + } + + /* Set an anonymous, inactive session for services that need no session */ + UA_Session anonymousSession; + if(!session) { + if(sessionRequired) { + UA_LOG_WARNING_CHANNEL(server->config.logger, channel, + "Service request %i without a valid session", + requestType->binaryEncodingId); + UA_deleteMembers(request, requestType); + return sendServiceFault(channel, msg, requestPos, responseType, + requestId, UA_STATUSCODE_BADSESSIONIDINVALID); + } + + UA_Session_init(&anonymousSession); + anonymousSession.sessionId = UA_NODEID_GUID(0, UA_GUID_NULL); + anonymousSession.header.channel = channel; + session = &anonymousSession; + } + + /* Trying to use a non-activated session? */ + if(sessionRequired && !session->activated) { + UA_LOG_WARNING_SESSION(server->config.logger, session, + "Calling service %i on a non-activated session", + requestType->binaryEncodingId); + UA_SessionManager_removeSession(&server->sessionManager, + &session->header.authenticationToken); + UA_deleteMembers(request, requestType); + return sendServiceFault(channel, msg, requestPos, responseType, + requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED); + } + + /* The session is bound to another channel */ + if(session != &anonymousSession && session->header.channel != channel) { + UA_LOG_WARNING_CHANNEL(server->config.logger, channel, + "Client tries to use a Session that is not " + "bound to this SecureChannel"); + UA_deleteMembers(request, requestType); + return sendServiceFault(channel, msg, requestPos, responseType, + requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID); + } + + /* Update the session lifetime */ + UA_Session_updateLifetime(session); + +#ifdef UA_ENABLE_SUBSCRIPTIONS + /* The publish request is not answered immediately */ + if(requestType == &UA_TYPES[UA_TYPES_PUBLISHREQUEST]) { + Service_Publish(server, session, + (const UA_PublishRequest*)request, requestId); + UA_deleteMembers(request, requestType); + return UA_STATUSCODE_GOOD; + } +#endif + + send_response: + + /* Prepare the ResponseHeader */ + ((UA_ResponseHeader*)response)->requestHandle = requestHeader->requestHandle; + ((UA_ResponseHeader*)response)->timestamp = UA_DateTime_now(); + + /* Process normal services before initializing the message context. + * Some services may initialize new message contexts and to support network + * layers only providing one send buffer, only one message context can be + * initialized concurrently. */ + if(serviceType == UA_SERVICETYPE_NORMAL) + service(server, session, request, response); + + /* Start the message */ + UA_NodeId typeId = UA_NODEID_NUMERIC(0, responseType->binaryEncodingId); + UA_MessageContext mc; + retval = UA_MessageContext_begin(&mc, channel, requestId, UA_MESSAGETYPE_MSG); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Assert's required for clang-analyzer */ + UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURE_MESSAGE_HEADER_LENGTH]); + UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]); + + retval = UA_MessageContext_encode(&mc, &typeId, &UA_TYPES[UA_TYPES_NODEID]); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + switch(serviceType) { + case UA_SERVICETYPE_CUSTOM: + /* Was processed before...*/ + retval = UA_MessageContext_encode(&mc, response, responseType); + break; + case UA_SERVICETYPE_INSITU: + retval = serviceInsitu + (server, session, &mc, request, (UA_ResponseHeader*)response); + break; + case UA_SERVICETYPE_NORMAL: + default: + retval = UA_MessageContext_encode(&mc, response, responseType); + break; + } + + /* Finish sending the message */ + if(retval != UA_STATUSCODE_GOOD) { + UA_MessageContext_abort(&mc); + goto cleanup; + } + + retval = UA_MessageContext_finish(&mc); + + cleanup: + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Could not send the message over the SecureChannel " + "with StatusCode %s", UA_StatusCode_name(retval)); + /* Clean up */ + UA_deleteMembers(request, requestType); + UA_deleteMembers(response, responseType); + return retval; +} + +/* Takes decoded messages starting at the nodeid of the content type. */ +static UA_StatusCode +processSecureChannelMessage(void *application, UA_SecureChannel *channel, + UA_MessageType messagetype, UA_UInt32 requestId, + const UA_ByteString *message) { + UA_Server *server = (UA_Server*)application; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + switch(messagetype) { + case UA_MESSAGETYPE_OPN: + UA_LOG_TRACE_CHANNEL(server->config.logger, channel, + "Process an OPN on an open channel"); + retval = processOPN(server, channel, requestId, message); + break; + case UA_MESSAGETYPE_MSG: + UA_LOG_TRACE_CHANNEL(server->config.logger, channel, "Process a MSG"); + retval = processMSG(server, channel, requestId, message); + break; + case UA_MESSAGETYPE_CLO: + UA_LOG_TRACE_CHANNEL(server->config.logger, channel, "Process a CLO"); + Service_CloseSecureChannel(server, channel); + break; + default: + UA_LOG_TRACE_CHANNEL(server->config.logger, channel, "Invalid message type"); + retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + break; + } + return retval; +} + +static UA_StatusCode +createSecureChannel(void *application, UA_Connection *connection, + UA_AsymmetricAlgorithmSecurityHeader *asymHeader) { + UA_Server *server = (UA_Server*)application; + + /* Iterate over available endpoints and choose the correct one */ + UA_Endpoint *endpoint = NULL; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < server->config.endpointsSize; ++i) { + UA_Endpoint *endpointCandidate = &server->config.endpoints[i]; + if(!UA_ByteString_equal(&asymHeader->securityPolicyUri, + &endpointCandidate->securityPolicy.policyUri)) + continue; + retval = endpointCandidate->securityPolicy.asymmetricModule. + compareCertificateThumbprint(&endpointCandidate->securityPolicy, + &asymHeader->receiverCertificateThumbprint); + if(retval != UA_STATUSCODE_GOOD) + continue; + + /* We found the correct endpoint (except for security mode) The endpoint + * needs to be changed by the client / server to match the security + * mode. The server does this in the securechannel manager */ + endpoint = endpointCandidate; + break; + } + + if(!endpoint) + return UA_STATUSCODE_BADSECURITYPOLICYREJECTED; + + /* Create a new channel */ + return UA_SecureChannelManager_create(&server->secureChannelManager, connection, + &endpoint->securityPolicy, asymHeader); +} + +static UA_StatusCode +processCompleteChunkWithoutChannel(UA_Server *server, UA_Connection *connection, + UA_ByteString *message) { + /* Process chunk without a channel; must be OPN */ + UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | No channel attached to the connection. " + "Process the chunk directly", connection->sockfd); + size_t offset = 0; + UA_TcpMessageHeader tcpMessageHeader; + UA_StatusCode retval = + UA_TcpMessageHeader_decodeBinary(message, &offset, &tcpMessageHeader); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + // Only HEL and OPN messages possible without a channel (on the server side) + switch(tcpMessageHeader.messageTypeAndChunkType & 0x00ffffff) { + case UA_MESSAGETYPE_HEL: + retval = processHEL(server, connection, message, &offset); + break; + case UA_MESSAGETYPE_OPN: + { + UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Process OPN message", connection->sockfd); + + /* Called before HEL */ + if(connection->state != UA_CONNECTION_ESTABLISHED) { + retval = UA_STATUSCODE_BADCOMMUNICATIONERROR; + break; + } + + // Decode the asymmetric algorithm security header since it is not encrypted and + // needed to decide what security policy to use. + UA_AsymmetricAlgorithmSecurityHeader asymHeader; + UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); + size_t messageHeaderOffset = UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH; + retval = UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(message, + &messageHeaderOffset, + &asymHeader); + if(retval != UA_STATUSCODE_GOOD) + break; + + retval = createSecureChannel(server, connection, &asymHeader); + UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); + if(retval != UA_STATUSCODE_GOOD) + break; + + retval = UA_SecureChannel_processChunk(connection->channel, message, + processSecureChannelMessage, + server, UA_FALSE); + if(retval != UA_STATUSCODE_GOOD) + break; + break; + } + default: + UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Expected OPN or HEL message on a connection " + "without a SecureChannel", connection->sockfd); + retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + break; + } + return retval; +} + +static UA_StatusCode +processCompleteChunk(void *const application, + UA_Connection *const connection, + UA_ByteString *const chunk) { + UA_Server *const server = (UA_Server*)application; +#ifdef UA_DEBUG_DUMP_PKGS_FILE + UA_debug_dumpCompleteChunk(server, connection, chunk); +#endif + if(!connection->channel) + return processCompleteChunkWithoutChannel(server, connection, chunk); + return UA_SecureChannel_processChunk(connection->channel, chunk, + processSecureChannelMessage, + server, UA_FALSE); +} + +static void +processBinaryMessage(UA_Server *server, UA_Connection *connection, + UA_ByteString *message) { + UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Received a packet.", connection->sockfd); +#ifdef UA_DEBUG_DUMP_PKGS + UA_dump_hex_pkg(message->data, message->length); +#endif + + UA_StatusCode retval = UA_Connection_processChunks(connection, server, + processCompleteChunk, message); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Processing the message failed with " + "error %s", connection->sockfd, UA_StatusCode_name(retval)); + /* Send an ERR message and close the connection */ + UA_TcpErrorMessage error; + error.error = retval; + error.reason = UA_STRING_NULL; + UA_Connection_sendError(connection, &error); + connection->close(connection); + } +} + +#ifndef UA_ENABLE_MULTITHREADING + +void +UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, + UA_ByteString *message) { + processBinaryMessage(server, connection, message); +} + +#else + +typedef struct { + UA_Connection *connection; + UA_ByteString message; +} ConnectionMessage; + +static void +workerProcessBinaryMessage(UA_Server *server, ConnectionMessage *cm) { + processBinaryMessage(server, cm->connection, &cm->message); + UA_free(cm); +} + +void +UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, + UA_ByteString *message) { + /* Allocate the memory for the callback data */ + ConnectionMessage *cm = (ConnectionMessage*)UA_malloc(sizeof(ConnectionMessage)); + + /* If malloc failed, execute immediately */ + if(!cm) { + processBinaryMessage(server, connection, message); + return; + } + + /* Dispatch to the workers */ + cm->connection = connection; + cm->message = *message; + UA_Server_workerCallback(server, (UA_ServerCallback)workerProcessBinaryMessage, cm); +} + +static void +deleteConnectionTrampoline(UA_Server *server, void *data) { + UA_Connection *connection = (UA_Connection*)data; + connection->free(connection); +} +#endif + +void +UA_Server_removeConnection(UA_Server *server, UA_Connection *connection) { + UA_Connection_detachSecureChannel(connection); +#ifndef UA_ENABLE_MULTITHREADING + connection->free(connection); +#else + UA_Server_delayedCallback(server, deleteConnectionTrampoline, connection); +#endif +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2016-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2016 (c) Lorenz Haas + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Florian Palm + * Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Julian Grothoff + */ + + +#define UA_MAX_TREE_RECURSE 50 /* How deep up/down the tree do we recurse at most? */ + +/**********************/ +/* Parse NumericRange */ +/**********************/ + +static size_t +readDimension(UA_Byte *buf, size_t buflen, UA_NumericRangeDimension *dim) { + size_t progress = UA_readNumber(buf, buflen, &dim->min); + if(progress == 0) + return 0; + if(buflen <= progress + 1 || buf[progress] != ':') { + dim->max = dim->min; + return progress; + } + + ++progress; + size_t progress2 = UA_readNumber(&buf[progress], buflen - progress, &dim->max); + if(progress2 == 0) + return 0; + + /* invalid range */ + if(dim->min >= dim->max) + return 0; + + return progress + progress2; +} + +UA_StatusCode +UA_NumericRange_parseFromString(UA_NumericRange *range, const UA_String *str) { + size_t idx = 0; + size_t dimensionsMax = 0; + UA_NumericRangeDimension *dimensions = NULL; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + size_t offset = 0; + while(true) { + /* alloc dimensions */ + if(idx >= dimensionsMax) { + UA_NumericRangeDimension *newds; + size_t newdssize = sizeof(UA_NumericRangeDimension) * (dimensionsMax + 2); + newds = (UA_NumericRangeDimension*)UA_realloc(dimensions, newdssize); + if(!newds) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + break; + } + dimensions = newds; + dimensionsMax = dimensionsMax + 2; + } + + /* read the dimension */ + size_t progress = readDimension(&str->data[offset], str->length - offset, + &dimensions[idx]); + if(progress == 0) { + retval = UA_STATUSCODE_BADINDEXRANGEINVALID; + break; + } + offset += progress; + ++idx; + + /* loop into the next dimension */ + if(offset >= str->length) + break; + + if(str->data[offset] != ',') { + retval = UA_STATUSCODE_BADINDEXRANGEINVALID; + break; + } + ++offset; + } + + if(retval == UA_STATUSCODE_GOOD && idx > 0) { + range->dimensions = dimensions; + range->dimensionsSize = idx; + } else + UA_free(dimensions); + + return retval; +} + +/********************************/ +/* 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_Nodestore *ns, 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 = ns->getNode(ns->context, 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->targetIdsSize; ++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 = UA_FALSE; + while(!skip && last) { + if(UA_NodeId_equal(last->id, &refs->targetIds[j].nodeId)) + skip = UA_TRUE; + last = last->parent; + } + if(skip) + continue; + } + + /* Stack-allocate the visitedRefs structure for the next depth */ + struct ref_history nextVisitedRefs = {visitedRefs, &refs->targetIds[j].nodeId, + (UA_UInt16)(visitedRefs->depth+1)}; + + /* Recurse */ + UA_Boolean foundRecursive = + isNodeInTreeNoCircular(ns, &refs->targetIds[j].nodeId, nodeToFind, &nextVisitedRefs, + referenceTypeIds, referenceTypeIdsSize); + if(foundRecursive) { + ns->releaseNode(ns->context, node); + return true; + } + } + } + + ns->releaseNode(ns->context, node); + return false; +} + +UA_Boolean +isNodeInTree(UA_Nodestore *ns, const UA_NodeId *leafNode, const UA_NodeId *nodeToFind, + const UA_NodeId *referenceTypeIds, size_t referenceTypeIdsSize) { + struct ref_history visitedRefs = {NULL, leafNode, 0}; + return isNodeInTreeNoCircular(ns, leafNode, nodeToFind, &visitedRefs, referenceTypeIds, referenceTypeIdsSize); +} + +const UA_Node * +getNodeType(UA_Server *server, const UA_Node *node) { + /* The reference to the parent is different for variable and variabletype */ + UA_NodeId parentRef; + UA_Boolean inverse; + UA_NodeClass typeNodeClass; + switch(node->nodeClass) { + case UA_NODECLASS_OBJECT: + parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); + inverse = false; + typeNodeClass = UA_NODECLASS_OBJECTTYPE; + break; + case UA_NODECLASS_VARIABLE: + parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); + inverse = false; + typeNodeClass = UA_NODECLASS_VARIABLETYPE; + break; + case UA_NODECLASS_OBJECTTYPE: + case UA_NODECLASS_VARIABLETYPE: + case UA_NODECLASS_REFERENCETYPE: + case UA_NODECLASS_DATATYPE: + parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); + inverse = true; + typeNodeClass = node->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)) + continue; + UA_assert(node->references[i].targetIdsSize > 0); + const UA_NodeId *targetId = &node->references[i].targetIds[0].nodeId; + const UA_Node *type = UA_Nodestore_get(server, targetId); + if(!type) + continue; + if(type->nodeClass == typeNodeClass) + return type; + 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)) + return true; + if(node->references[i].isInverse == true && + UA_NodeId_equal(&node->references[i].referenceTypeId, &hasTypeDefinition)) + return true; + } + return false; +} + +static const UA_NodeId hasSubtypeNodeId = + {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}}; + +static UA_StatusCode +getTypeHierarchyFromNode(UA_NodeId **results_ptr, size_t *results_count, + size_t *results_size, const UA_Node *node) { + UA_NodeId *results = *results_ptr; + for(size_t i = 0; i < node->referencesSize; ++i) { + /* Is the reference kind relevant? */ + UA_NodeReferenceKind *refs = &node->references[i]; + if(!refs->isInverse) + continue; + if(!UA_NodeId_equal(&hasSubtypeNodeId, &refs->referenceTypeId)) + continue; + + /* Append all targets of the reference kind .. if not a duplicate */ + for(size_t j = 0; j < refs->targetIdsSize; ++j) { + /* Is the target a duplicate? (multi-inheritance) */ + UA_NodeId *targetId = &refs->targetIds[j].nodeId; + UA_Boolean duplicate = false; + for(size_t k = 0; k < *results_count; ++k) { + if(UA_NodeId_equal(targetId, &results[k])) { + duplicate = true; + break; + } + } + if(duplicate) + continue; + + /* Increase array length if necessary */ + if(*results_count >= *results_size) { + size_t new_size = sizeof(UA_NodeId) * (*results_size) * 2; + UA_NodeId *new_results = (UA_NodeId*)UA_realloc(results, new_size); + if(!new_results) { + UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + results = new_results; + *results_ptr = results; + *results_size *= 2; + } + + /* Copy new nodeid to the end of the list */ + UA_StatusCode retval = UA_NodeId_copy(targetId, &results[*results_count]); + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]); + return retval; + } + *results_count += 1; + } + } + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +getTypeHierarchy(UA_Nodestore *ns, const UA_NodeId *leafType, + UA_NodeId **typeHierarchy, size_t *typeHierarchySize) { + /* Allocate the results array. Probably too big, but saves mallocs. */ + size_t results_size = 20; + UA_NodeId *results = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * results_size); + if(!results) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* The leaf is the first element */ + size_t results_count = 1; + UA_StatusCode retval = UA_NodeId_copy(leafType, &results[0]); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(results); + return retval; + } + + /* Loop over the array members .. and add new elements to the end */ + for(size_t idx = 0; idx < results_count; ++idx) { + /* Get the node */ + const UA_Node *node = ns->getNode(ns->context, &results[idx]); + + /* Invalid node, remove from the array */ + if(!node) { + for(size_t i = idx; i < results_count-1; ++i) + results[i] = results[i+1]; + results_count--; + continue; + } + + /* Add references from the current node to the end of the array */ + retval = getTypeHierarchyFromNode(&results, &results_count, + &results_size, node); + + /* Release the node */ + ns->releaseNode(ns->context, node); + + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(results, results_count, &UA_TYPES[UA_TYPES_NODEID]); + return retval; + } + } + + /* Zero results. The leaf node was not found */ + if(results_count == 0) { + UA_free(results); + results = NULL; + } + + *typeHierarchy = results; + *typeHierarchySize = results_count; + return UA_STATUSCODE_GOOD; +} + +/* For mulithreading: make a copy of the node, edit and replace. + * For singlethreading: edit the original */ +UA_StatusCode +UA_Server_editNode(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, UA_EditNodeCallback callback, + void *data) { +#ifndef UA_ENABLE_MULTITHREADING + const UA_Node *node = UA_Nodestore_get(server, nodeId); + if(!node) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + UA_StatusCode retval = callback(server, session, + (UA_Node*)(uintptr_t)node, data); + UA_Nodestore_release(server, node); + return retval; +#else + UA_StatusCode retval; + do { + UA_Node *node; + retval = server->config.nodestore.getNodeCopy(server->config.nodestore.context, + nodeId, &node); + if(retval != UA_STATUSCODE_GOOD) + return retval; + retval = callback(server, session, node, data); + if(retval != UA_STATUSCODE_GOOD) { + server->config.nodestore.deleteNode(server->config.nodestore.context, node); + return retval; + } + retval = server->config.nodestore.replaceNode(server->config.nodestore.context, node); + } while(retval != UA_STATUSCODE_GOOD); + return retval; +#endif +} + +UA_StatusCode +UA_Server_processServiceOperations(UA_Server *server, UA_Session *session, + UA_ServiceOperation operationCallback, + void *context, const size_t *requestOperations, + const UA_DataType *requestOperationsType, + size_t *responseOperations, + const UA_DataType *responseOperationsType) { + size_t ops = *requestOperations; + if(ops == 0) + return UA_STATUSCODE_BADNOTHINGTODO; + + /* No padding after size_t */ + void **respPos = (void**)((uintptr_t)responseOperations + sizeof(size_t)); + *respPos = UA_Array_new(ops, responseOperationsType); + if(!(*respPos)) + return UA_STATUSCODE_BADOUTOFMEMORY; + + *responseOperations = ops; + uintptr_t respOp = (uintptr_t)*respPos; + /* No padding after size_t */ + uintptr_t reqOp = *(uintptr_t*)((uintptr_t)requestOperations + sizeof(size_t)); + for(size_t i = 0; i < ops; i++) { + operationCallback(server, session, context, (void*)reqOp, (void*)respOp); + reqOp += requestOperationsType->memSize; + respOp += responseOperationsType->memSize; + } + return UA_STATUSCODE_GOOD; +} + +/*********************************/ +/* Default attribute definitions */ +/*********************************/ + +const UA_ObjectAttributes UA_ObjectAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + 0 /* eventNotifier */ +}; + +const UA_VariableAttributes UA_VariableAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + {NULL, UA_VARIANT_DATA, + 0, NULL, 0, NULL}, /* value */ + {0, UA_NODEIDTYPE_NUMERIC, + {UA_NS0ID_BASEDATATYPE}}, /* dataType */ + UA_VALUERANK_ANY, /* valueRank */ + 0, NULL, /* arrayDimensions */ + UA_ACCESSLEVELMASK_READ, 0, /* accessLevel (userAccessLevel) */ + 0.0, /* minimumSamplingInterval */ + false /* historizing */ +}; + +const UA_MethodAttributes UA_MethodAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + true, true /* executable (userExecutable) */ +}; + +const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + false /* isAbstract */ +}; + +const UA_VariableTypeAttributes UA_VariableTypeAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + {NULL, UA_VARIANT_DATA, + 0, NULL, 0, NULL}, /* value */ + {0, UA_NODEIDTYPE_NUMERIC, + {UA_NS0ID_BASEDATATYPE}}, /* dataType */ + UA_VALUERANK_ANY, /* valueRank */ + 0, NULL, /* arrayDimensions */ + false /* isAbstract */ +}; + +const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + false, /* isAbstract */ + false, /* symmetric */ + {{0, NULL}, {0, NULL}} /* inverseName */ +}; + +const UA_DataTypeAttributes UA_DataTypeAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + false /* isAbstract */ +}; + +const UA_ViewAttributes UA_ViewAttributes_default = { + 0, /* specifiedAttributes */ + {{0, NULL}, {0, NULL}}, /* displayName */ + {{0, NULL}, {0, NULL}}, /* description */ + 0, 0, /* writeMask (userWriteMask) */ + false, /* containsNoLoops */ + 0 /* eventNotifier */ +}; + + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/server/ua_server_worker.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-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * 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 + */ + +#ifdef UA_ENABLE_VALGRIND_INTERACTIVE +#include <valgrind/memcheck.h> +#endif + +#define UA_MAXTIMEOUT 50 /* Max timeout in ms between main-loop iterations */ + +/** + * Worker Threads and Dispatch Queue + * --------------------------------- + * The worker threads dequeue callbacks from a central Multi-Producer + * Multi-Consumer Queue (MPMC). When there are no callbacks, workers go idle. + * The condition to wake them up is triggered whenever a callback is + * dispatched. + * + * 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. */ + +#ifdef UA_ENABLE_MULTITHREADING + +struct UA_Worker { + UA_Server *server; + pthread_t thr; + UA_UInt32 counter; + volatile UA_Boolean running; + + /* separate cache lines */ + char padding[64 - sizeof(void*) - sizeof(pthread_t) - + sizeof(UA_UInt32) - sizeof(UA_Boolean)]; +}; + +struct UA_WorkerCallback { + SIMPLEQ_ENTRY(UA_WorkerCallback) next; + UA_ServerCallback callback; + void *data; + + UA_Boolean delayed; /* Is it a delayed callback? */ + UA_Boolean countersSampled; /* Have the worker counters been sampled? */ + UA_UInt32 workerCounters[]; /* Counter value for each worker */ +}; +typedef struct UA_WorkerCallback WorkerCallback; + +/* Forward Declaration */ +static void +processDelayedCallback(UA_Server *server, WorkerCallback *dc); + +static void * +workerLoop(UA_Worker *worker) { + UA_Server *server = worker->server; + 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); + + while(*running) { + UA_atomic_addUInt32(counter, 1); + pthread_mutex_lock(&server->dispatchQueue_accessMutex); + WorkerCallback *dc = SIMPLEQ_FIRST(&server->dispatchQueue); + if(dc) { + SIMPLEQ_REMOVE_HEAD(&server->dispatchQueue, next); + } + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + if(!dc) { + /* Nothing to do. Sleep until a callback is dispatched */ + pthread_mutex_lock(&server->dispatchQueue_conditionMutex); + pthread_cond_wait(&server->dispatchQueue_condition, + &server->dispatchQueue_conditionMutex); + pthread_mutex_unlock(&server->dispatchQueue_conditionMutex); + continue; + } + + if(dc->delayed) { + processDelayedCallback(server, dc); + continue; + } + + dc->callback(server, dc->data); + UA_free(dc); + } + + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "Worker shut down"); + return NULL; +} + +void UA_Server_cleanupDispatchQueue(UA_Server *server) { + while(true) { + pthread_mutex_lock(&server->dispatchQueue_accessMutex); + WorkerCallback *dc = SIMPLEQ_FIRST(&server->dispatchQueue); + if(!dc) { + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + break; + } + SIMPLEQ_REMOVE_HEAD(&server->dispatchQueue, next); + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + dc->callback(server, dc->data); + UA_free(dc); + } +} + +#endif + +/** + * Repeated Callbacks + * ------------------ + * Repeated Callbacks are handled by UA_Timer (used in both client and server). + * In the multi-threaded case, callbacks are dispatched to workers. Otherwise, + * they are executed immediately. */ + +void +UA_Server_workerCallback(UA_Server *server, UA_ServerCallback callback, + void *data) { +#ifndef UA_ENABLE_MULTITHREADING + /* Execute immediately */ + callback(server, data); +#else + /* Execute immediately if memory could not be allocated */ + WorkerCallback *dc = (WorkerCallback*)UA_malloc(sizeof(WorkerCallback)); + if(!dc) { + callback(server, data); + return; + } + + /* Enqueue for the worker threads */ + dc->callback = callback; + dc->data = data; + dc->delayed = false; + pthread_mutex_lock(&server->dispatchQueue_accessMutex); + SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next); + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + + /* Wake up sleeping workers */ + pthread_cond_broadcast(&server->dispatchQueue_condition); +#endif +} + +/** + * Delayed Callbacks + * ----------------- + * + * Delayed Callbacks are called only when all callbacks that were dispatched + * prior are finished. In the single-threaded case, the callback is added to a + * singly-linked list that is processed at the end of the server's main-loop. In + * the multi-threaded case, the delay is ensure by a three-step procedure: + * + * 1. The delayed callback is dispatched to the worker queue. So it is only + * dequeued when all prior callbacks have been dequeued. + * + * 2. When the callback is first dequeued by a worker, sample the counter of all + * workers. Once all counters have advanced, the callback is ready. + * + * 3. Check regularly if the callback is ready by adding it back to the dispatch + * queue. */ + +/* Delayed callback to free the subscription memory */ +static void +freeCallback(UA_Server *server, void *data) { + UA_free(data); +} + +/* TODO: Delayed free should never fail. This can be achieved by adding a prefix + * with the list pointers */ +UA_StatusCode +UA_Server_delayedFree(UA_Server *server, void *data) { + return UA_Server_delayedCallback(server, freeCallback, data); +} + +#ifndef UA_ENABLE_MULTITHREADING + +typedef struct UA_DelayedCallback { + SLIST_ENTRY(UA_DelayedCallback) next; + UA_ServerCallback callback; + void *data; +} UA_DelayedCallback; + +UA_StatusCode +UA_Server_delayedCallback(UA_Server *server, UA_ServerCallback callback, + void *data) { + UA_DelayedCallback *dc = + (UA_DelayedCallback*)UA_malloc(sizeof(UA_DelayedCallback)); + if(!dc) + return UA_STATUSCODE_BADOUTOFMEMORY; + + dc->callback = callback; + dc->data = data; + SLIST_INSERT_HEAD(&server->delayedCallbacks, dc, next); + return UA_STATUSCODE_GOOD; +} + +void UA_Server_cleanupDelayedCallbacks(UA_Server *server) { + UA_DelayedCallback *dc, *dc_tmp; + SLIST_FOREACH_SAFE(dc, &server->delayedCallbacks, next, dc_tmp) { + SLIST_REMOVE(&server->delayedCallbacks, dc, UA_DelayedCallback, next); + dc->callback(server, dc->data); + UA_free(dc); + } +} + +#else /* UA_ENABLE_MULTITHREADING */ + +UA_StatusCode +UA_Server_delayedCallback(UA_Server *server, UA_ServerCallback callback, + void *data) { + size_t dcsize = sizeof(WorkerCallback) + + (sizeof(UA_UInt32) * server->config.nThreads); + WorkerCallback *dc = (WorkerCallback*)UA_malloc(dcsize); + if(!dc) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Enqueue for the worker threads */ + dc->callback = callback; + dc->data = data; + dc->delayed = true; + dc->countersSampled = false; + pthread_mutex_lock(&server->dispatchQueue_accessMutex); + SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next); + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + + /* Wake up sleeping workers */ + pthread_cond_broadcast(&server->dispatchQueue_condition); + return UA_STATUSCODE_GOOD; +} + +/* Called from the worker loop */ +static void +processDelayedCallback(UA_Server *server, WorkerCallback *dc) { + /* Set the worker counters */ + if(!dc->countersSampled) { + for(size_t i = 0; i < server->config.nThreads; ++i) + dc->workerCounters[i] = server->workers[i].counter; + dc->countersSampled = true; + + /* Re-add to the dispatch queue */ + pthread_mutex_lock(&server->dispatchQueue_accessMutex); + SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next); + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + + /* Wake up sleeping workers */ + pthread_cond_broadcast(&server->dispatchQueue_condition); + return; + } + + /* Have all other jobs finished? */ + UA_Boolean ready = true; + for(size_t i = 0; i < server->config.nThreads; ++i) { + if(dc->workerCounters[i] == server->workers[i].counter) { + ready = false; + break; + } + } + + /* Re-add to the dispatch queue. + * TODO: What is the impact of this loop? + * Can we add a small delay here? */ + if(!ready) { + pthread_mutex_lock(&server->dispatchQueue_accessMutex); + SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next); + pthread_mutex_unlock(&server->dispatchQueue_accessMutex); + + /* Wake up sleeping workers */ + pthread_cond_broadcast(&server->dispatchQueue_condition); + return; + } + + /* Execute the callback */ + dc->callback(server, dc->data); + UA_free(dc); +} + +#endif + +/** + * Main Server Loop + * ---------------- + * Start: Spin up the workers and the network layer and sample the server's + * start time. + * Iterate: Process repeated callbacks and events in the network layer. + * This part can be driven from an external main-loop in an + * event-driven single-threaded architecture. + * Stop: Stop workers, finish all callbacks, stop the network layer, + * clean up */ + +UA_StatusCode +UA_Server_run_startup(UA_Server *server) { + UA_Variant var; + UA_StatusCode result = UA_STATUSCODE_GOOD; + + /* Sample the start time and set it to the Server object */ + server->startTime = UA_DateTime_now(); + UA_Variant_init(&var); + UA_Variant_setScalar(&var, &server->startTime, &UA_TYPES[UA_TYPES_DATETIME]); + UA_Server_writeValue(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME), + var); + + /* Start the networklayers */ + for(size_t i = 0; i < server->config.networkLayersSize; ++i) { + UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; + result |= nl->start(nl, &server->config.customHostname); + } + + /* Spin up the worker threads */ +#ifdef UA_ENABLE_MULTITHREADING + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Spinning up %u worker thread(s)", server->config.nThreads); + pthread_mutex_init(&server->dispatchQueue_accessMutex, NULL); + pthread_cond_init(&server->dispatchQueue_condition, NULL); + pthread_mutex_init(&server->dispatchQueue_conditionMutex, NULL); + server->workers = (UA_Worker*)UA_malloc(server->config.nThreads * sizeof(UA_Worker)); + if(!server->workers) + return UA_STATUSCODE_BADOUTOFMEMORY; + for(size_t i = 0; i < server->config.nThreads; ++i) { + UA_Worker *worker = &server->workers[i]; + worker->server = server; + worker->counter = 0; + worker->running = true; + pthread_create(&worker->thr, NULL, (void* (*)(void*))workerLoop, worker); + } +#endif + + /* Start the multicast discovery server */ +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + if(server->config.applicationDescription.applicationType == + UA_APPLICATIONTYPE_DISCOVERYSERVER) + startMulticastDiscoveryServer(server); +#endif + + return result; +} + +UA_UInt16 +UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) { + /* Process repeated work */ + UA_DateTime now = UA_DateTime_nowMonotonic(); + UA_DateTime nextRepeated = + UA_Timer_process(&server->timer, now, + (UA_TimerDispatchCallback)UA_Server_workerCallback, + server); + UA_DateTime latest = now + (UA_MAXTIMEOUT * UA_DATETIME_MSEC); + if(nextRepeated > latest) + nextRepeated = latest; + + UA_UInt16 timeout = 0; + + /* round always to upper value to avoid timeout to be set to 0 + * if(nextRepeated - now) < (UA_DATETIME_MSEC/2) */ + if(waitInternal) + timeout = (UA_UInt16)(((nextRepeated - now) + (UA_DATETIME_MSEC - 1)) / UA_DATETIME_MSEC); + + /* Listen on the networklayer */ + for(size_t i = 0; i < server->config.networkLayersSize; ++i) { + UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; + nl->listen(nl, server, timeout); + } + +#ifndef UA_ENABLE_MULTITHREADING + /* Process delayed callbacks when all callbacks and network events are done. + * If multithreading is enabled, the cleanup of delayed values is attempted + * by a callback in the job queue. */ + UA_Server_cleanupDelayedCallbacks(server); +#endif + +#if defined(UA_ENABLE_DISCOVERY_MULTICAST) && !defined(UA_ENABLE_MULTITHREADING) + if(server->config.applicationDescription.applicationType == + UA_APPLICATIONTYPE_DISCOVERYSERVER) { + // 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, UA_TRUE); + if(hasNext == UA_STATUSCODE_GOOD && multicastNextRepeat < nextRepeated) + nextRepeated = multicastNextRepeat; + } +#endif + + now = UA_DateTime_nowMonotonic(); + timeout = 0; + if(nextRepeated > now) + timeout = (UA_UInt16)((nextRepeated - now) / UA_DATETIME_MSEC); + return timeout; +} + +UA_StatusCode +UA_Server_run_shutdown(UA_Server *server) { + /* Stop the netowrk layer */ + for(size_t i = 0; i < server->config.networkLayersSize; ++i) { + UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; + nl->stop(nl, server); + } + +#ifdef UA_ENABLE_MULTITHREADING + /* Shut down the workers */ + if(server->workers) { + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Shutting down %u worker thread(s)", + server->config.nThreads); + for(size_t i = 0; i < server->config.nThreads; ++i) + server->workers[i].running = false; + pthread_cond_broadcast(&server->dispatchQueue_condition); + for(size_t i = 0; i < server->config.nThreads; ++i) + pthread_join(server->workers[i].thr, NULL); + UA_free(server->workers); + server->workers = NULL; + } + + /* Execute the remaining callbacks in the dispatch queue. Also executes + * delayed callbacks. */ + UA_Server_cleanupDispatchQueue(server); +#else + /* Process remaining delayed callbacks */ + UA_Server_cleanupDelayedCallbacks(server); +#endif + +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + /* Stop multicast discovery */ + if(server->config.applicationDescription.applicationType == + UA_APPLICATIONTYPE_DISCOVERYSERVER) + stopMulticastDiscoveryServer(server); +#endif + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_run(UA_Server *server, volatile UA_Boolean *running) { + UA_StatusCode retval = UA_Server_run_startup(server); + if(retval != UA_STATUSCODE_GOOD) + return retval; +#ifdef UA_ENABLE_VALGRIND_INTERACTIVE + size_t loopCount = 0; +#endif + while(*running) { +#ifdef UA_ENABLE_VALGRIND_INTERACTIVE + if(loopCount == 0) { + VALGRIND_DO_LEAK_CHECK; + } + ++loopCount; + loopCount %= UA_VALGRIND_INTERACTIVE_INTERVAL; +#endif + UA_Server_run_iterate(server, true); + } + return UA_Server_run_shutdown(server); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef UA_ENABLE_DISCOVERY + +static UA_StatusCode +register_server_with_discovery_server(UA_Server *server, + const char* discoveryServerUrl, + const UA_Boolean isUnregister, + const char* semaphoreFilePath) { + if(!discoveryServerUrl) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "No discovery server url provided"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Create the client */ + UA_ClientConfig clientConfig = UA_Server_getClientConfig(); + UA_Client *client = UA_Client_new(clientConfig); + if(!client) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Connect the client */ + UA_StatusCode retval = UA_Client_connect(client, discoveryServerUrl); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_CLIENT, + "Connecting to the discovery server failed with statuscode %s", + UA_StatusCode_name(retval)); + UA_Client_disconnect(client); + UA_Client_delete(client); + return retval; + } + + /* Prepare the request. Do not cleanup the request after the service call, + * as the members are stack-allocated or point into the server config. */ + UA_RegisterServer2Request request; + UA_RegisterServer2Request_init(&request); + request.requestHeader.timestamp = UA_DateTime_now(); + request.requestHeader.timeoutHint = 10000; + + request.server.isOnline = !isUnregister; + request.server.serverUri = server->config.applicationDescription.applicationUri; + request.server.productUri = server->config.applicationDescription.productUri; + request.server.serverType = server->config.applicationDescription.applicationType; + request.server.gatewayServerUri = server->config.applicationDescription.gatewayServerUri; + + if(semaphoreFilePath) { +#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE + request.server.semaphoreFilePath = + UA_STRING((char*)(uintptr_t)semaphoreFilePath); /* dirty cast */ +#else + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_CLIENT, + "Ignoring semaphore file path. open62541 not compiled " + "with UA_ENABLE_DISCOVERY_SEMAPHORE=ON"); +#endif + } + + request.server.serverNames = &server->config.applicationDescription.applicationName; + request.server.serverNamesSize = 1; + + /* Copy 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; + + 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; + } + + UA_MdnsDiscoveryConfiguration mdnsConfig; + UA_MdnsDiscoveryConfiguration_init(&mdnsConfig); + + request.discoveryConfigurationSize = 1; + request.discoveryConfiguration = UA_ExtensionObject_new(); + UA_ExtensionObject_init(&request.discoveryConfiguration[0]); + 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 = &mdnsConfig; + + mdnsConfig.mdnsServerName = server->config.mdnsServerName; + mdnsConfig.serverCapabilities = server->config.serverCapabilities; + mdnsConfig.serverCapabilitiesSize = server->config.serverCapabilitiesSize; + + // First try with RegisterServer2, if that isn't implemented, use RegisterServer + UA_RegisterServer2Response response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST], + &response, &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE]); + + UA_StatusCode serviceResult = response.responseHeader.serviceResult; + UA_RegisterServer2Response_deleteMembers(&response); + UA_ExtensionObject_delete(request.discoveryConfiguration); + + if(serviceResult == UA_STATUSCODE_BADNOTIMPLEMENTED || + serviceResult == UA_STATUSCODE_BADSERVICEUNSUPPORTED) { + /* Try RegisterServer */ + UA_RegisterServerRequest request_fallback; + UA_RegisterServerRequest_init(&request_fallback); + /* Copy from RegisterServer2 request */ + request_fallback.requestHeader = request.requestHeader; + request_fallback.server = request.server; + + UA_RegisterServerResponse response_fallback; + + __UA_Client_Service(client, &request_fallback, + &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST], + &response_fallback, + &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE]); + + serviceResult = response_fallback.responseHeader.serviceResult; + UA_RegisterServerResponse_deleteMembers(&response_fallback); + } + + if(serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_CLIENT, + "RegisterServer/RegisterServer2 failed with statuscode %s", + UA_StatusCode_name(serviceResult)); + } + + UA_Client_disconnect(client); + UA_Client_delete(client); + return serviceResult; +} + +UA_StatusCode +UA_Server_register_discovery(UA_Server *server, const char* discoveryServerUrl, + const char* semaphoreFilePath) { + return register_server_with_discovery_server(server, discoveryServerUrl, + UA_FALSE, semaphoreFilePath); +} + +UA_StatusCode +UA_Server_unregister_discovery(UA_Server *server, const char* discoveryServerUrl) { + return register_server_with_discovery_server(server, discoveryServerUrl, + UA_TRUE, NULL); +} + +#endif /* UA_ENABLE_DISCOVERY */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/server/ua_securechannel_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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#define STARTCHANNELID 1 +#define STARTTOKENID 1 + +UA_StatusCode +UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_Server *server) { + TAILQ_INIT(&cm->channels); + // TODO: use an ID that is likely to be unique after a restart + cm->lastChannelId = STARTCHANNELID; + cm->lastTokenId = STARTTOKENID; + cm->currentChannelCount = 0; + cm->server = server; + return UA_STATUSCODE_GOOD; +} + +void +UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) { + channel_entry *entry, *temp; + TAILQ_FOREACH_SAFE(entry, &cm->channels, pointers, temp) { + TAILQ_REMOVE(&cm->channels, entry, pointers); + UA_SecureChannel_deleteMembersCleanup(&entry->channel); + UA_free(entry); + } +} + +static void +removeSecureChannelCallback(UA_Server *server, void *entry) { + channel_entry *centry = (channel_entry *)entry; + UA_SecureChannel_deleteMembersCleanup(¢ry->channel); + UA_free(entry); +} + +static UA_StatusCode +removeSecureChannel(UA_SecureChannelManager *cm, channel_entry *entry) { + /* Add a delayed callback to remove the channel when the currently + * scheduled jobs have completed */ + UA_StatusCode retval = UA_Server_delayedCallback(cm->server, removeSecureChannelCallback, entry); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(cm->server->config.logger, UA_LOGCATEGORY_SESSION, + "Could not remove the secure channel with error code %s", + UA_StatusCode_name(retval)); + return retval; /* Try again next time */ + } + + /* Detach the channel and make the capacity available */ + TAILQ_REMOVE(&cm->channels, entry, pointers); + UA_atomic_subUInt32(&cm->currentChannelCount, 1); + return UA_STATUSCODE_GOOD; +} + +/* remove channels that were not renewed or who have no connection attached */ +void +UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime nowMonotonic) { + channel_entry *entry, *temp; + TAILQ_FOREACH_SAFE(entry, &cm->channels, pointers, temp) { + UA_DateTime timeout = entry->channel.securityToken.createdAt + + (UA_DateTime)(entry->channel.securityToken.revisedLifetime * UA_DATETIME_MSEC); + if(timeout < nowMonotonic || !entry->channel.connection) { + UA_LOG_INFO_CHANNEL(cm->server->config.logger, &entry->channel, + "SecureChannel has timed out"); + removeSecureChannel(cm, entry); + } else if(entry->channel.nextSecurityToken.tokenId > 0) { + UA_SecureChannel_revolveTokens(&entry->channel); + } + } +} + +/* remove the first channel that has no session attached */ +static UA_Boolean +purgeFirstChannelWithoutSession(UA_SecureChannelManager *cm) { + channel_entry *entry; + TAILQ_FOREACH(entry, &cm->channels, pointers) { + if(LIST_EMPTY(&entry->channel.sessions)) { + UA_LOG_INFO_CHANNEL(cm->server->config.logger, &entry->channel, + "Channel was purged since maxSecureChannels was " + "reached and channel had no session attached"); + removeSecureChannel(cm, entry); + return true; + } + } + return false; +} + +UA_StatusCode +UA_SecureChannelManager_create(UA_SecureChannelManager *const cm, UA_Connection *const connection, + const UA_SecurityPolicy *const securityPolicy, + const UA_AsymmetricAlgorithmSecurityHeader *const asymHeader) { + /* connection already has a channel attached. */ + if(connection->channel != NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + /* 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(cm->currentChannelCount >= cm->server->config.maxSecureChannels && + !purgeFirstChannelWithoutSession(cm)) + return UA_STATUSCODE_BADOUTOFMEMORY; + + UA_LOG_INFO(cm->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; + + /* Create the channel context and parse the sender (remote) certificate used for the + * secureChannel. */ + UA_StatusCode retval = UA_SecureChannel_init(&entry->channel, securityPolicy, + &asymHeader->senderCertificate); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(entry); + return retval; + } + + /* Channel state is fresh (0) */ + entry->channel.securityToken.channelId = 0; + entry->channel.securityToken.tokenId = cm->lastTokenId++; + entry->channel.securityToken.createdAt = UA_DateTime_now(); + entry->channel.securityToken.revisedLifetime = cm->server->config.maxSecurityTokenLifetime; + + TAILQ_INSERT_TAIL(&cm->channels, entry, pointers); + UA_atomic_addUInt32(&cm->currentChannelCount, 1); + UA_Connection_attachSecureChannel(connection, &entry->channel); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_SecureChannel *channel, + const UA_OpenSecureChannelRequest *request, + UA_OpenSecureChannelResponse *response) { + if(channel->state != UA_SECURECHANNELSTATE_FRESH) { + UA_LOG_ERROR_CHANNEL(cm->server->config.logger, channel, + "Called open on already open or closed channel"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + if(request->securityMode != UA_MESSAGESECURITYMODE_NONE && + UA_ByteString_equal(&channel->securityPolicy->policyUri, &UA_SECURITY_POLICY_NONE_URI)) { + return UA_STATUSCODE_BADSECURITYMODEREJECTED; + } + + channel->securityMode = request->securityMode; + channel->securityToken.createdAt = UA_DateTime_nowMonotonic(); + channel->securityToken.channelId = cm->lastChannelId++; + channel->securityToken.createdAt = UA_DateTime_now(); + + /* Set the lifetime. Lifetime 0 -> set the maximum possible */ + channel->securityToken.revisedLifetime = + (request->requestedLifetime > cm->server->config.maxSecurityTokenLifetime) ? + cm->server->config.maxSecurityTokenLifetime : request->requestedLifetime; + if(channel->securityToken.revisedLifetime == 0) + channel->securityToken.revisedLifetime = cm->server->config.maxSecurityTokenLifetime; + + /* Set the nonces and generate the keys */ + UA_StatusCode retval = UA_ByteString_copy(&request->clientNonce, &channel->remoteNonce); + retval |= UA_SecureChannel_generateLocalNonce(channel); + retval |= UA_SecureChannel_generateNewKeys(channel); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Set the response */ + retval = UA_ByteString_copy(&channel->localNonce, &response->serverNonce); + retval |= UA_ChannelSecurityToken_copy(&channel->securityToken, &response->securityToken); + response->responseHeader.timestamp = UA_DateTime_now(); + response->responseHeader.requestHandle = request->requestHeader.requestHandle; + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* The channel is open */ + channel->state = UA_SECURECHANNELSTATE_OPEN; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_SecureChannel *channel, + const UA_OpenSecureChannelRequest *request, + UA_OpenSecureChannelResponse *response) { + if(channel->state != UA_SECURECHANNELSTATE_OPEN) { + UA_LOG_ERROR_CHANNEL(cm->server->config.logger, channel, + "Called renew on channel which is not open"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* If no security token is already issued */ + if(channel->nextSecurityToken.tokenId == 0) { + channel->nextSecurityToken.channelId = channel->securityToken.channelId; + channel->nextSecurityToken.tokenId = cm->lastTokenId++; + channel->nextSecurityToken.createdAt = UA_DateTime_now(); + channel->nextSecurityToken.revisedLifetime = + (request->requestedLifetime > cm->server->config.maxSecurityTokenLifetime) ? + cm->server->config.maxSecurityTokenLifetime : request->requestedLifetime; + if(channel->nextSecurityToken.revisedLifetime == 0) /* lifetime 0 -> return the max lifetime */ + channel->nextSecurityToken.revisedLifetime = cm->server->config.maxSecurityTokenLifetime; + } + + /* Replace the nonces */ + UA_ByteString_deleteMembers(&channel->remoteNonce); + UA_StatusCode retval = UA_ByteString_copy(&request->clientNonce, &channel->remoteNonce); + retval |= UA_SecureChannel_generateLocalNonce(channel); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Set the response */ + response->responseHeader.requestHandle = request->requestHeader.requestHandle; + retval = UA_ByteString_copy(&channel->localNonce, &response->serverNonce); + retval |= UA_ChannelSecurityToken_copy(&channel->nextSecurityToken, &response->securityToken); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Reset the internal creation date to the monotonic clock */ + channel->nextSecurityToken.createdAt = UA_DateTime_nowMonotonic(); + return UA_STATUSCODE_GOOD; +} + +UA_SecureChannel * +UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId) { + channel_entry *entry; + TAILQ_FOREACH(entry, &cm->channels, pointers) { + if(entry->channel.securityToken.channelId == channelId) + return &entry->channel; + } + return NULL; +} + +UA_StatusCode +UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) { + channel_entry *entry; + TAILQ_FOREACH(entry, &cm->channels, pointers) { + if(entry->channel.securityToken.channelId == channelId) + break; + } + if(!entry) + return UA_STATUSCODE_BADINTERNALERROR; + return removeSecureChannel(cm, entry); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/server/ua_session_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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2015 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +UA_StatusCode +UA_SessionManager_init(UA_SessionManager *sm, UA_Server *server) { + LIST_INIT(&sm->sessions); + sm->currentSessionCount = 0; + sm->server = server; + return UA_STATUSCODE_GOOD; +} + +/* Delayed callback to free the session memory */ +static void +removeSessionCallback(UA_Server *server, void *entry) { + session_list_entry *sentry = (session_list_entry*)entry; + UA_Session_deleteMembersCleanup(&sentry->session, server); + UA_free(sentry); +} + +static UA_StatusCode +removeSession(UA_SessionManager *sm, session_list_entry *sentry) { + /* Remove the Subscriptions */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_Subscription *sub, *tempsub; + LIST_FOREACH_SAFE(sub, &sentry->session.serverSubscriptions, listEntry, tempsub) { + UA_Session_deleteSubscription(sm->server, &sentry->session, sub->subscriptionId); + } + + UA_PublishResponseEntry *entry; + while((entry = UA_Session_dequeuePublishReq(&sentry->session))) { + UA_PublishResponse_deleteMembers(&entry->response); + UA_free(entry); + } +#endif + + /* Detach the Session from the SecureChannel */ + UA_Session_detachFromSecureChannel(&sentry->session); + + /* Deactivate the session */ + sentry->session.activated = false; + + /* Add a delayed callback to remove the session when the currently + * scheduled jobs have completed */ + UA_StatusCode retval = UA_Server_delayedCallback(sm->server, removeSessionCallback, sentry); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(sm->server->config.logger, &sentry->session, + "Could not remove session with error code %s", + UA_StatusCode_name(retval)); + return retval; /* Try again next time */ + } + + /* Detach the session from the session manager and make the capacity + * available */ + LIST_REMOVE(sentry, pointers); + UA_atomic_subUInt32(&sm->currentSessionCount, 1); + return UA_STATUSCODE_GOOD; +} + +void UA_SessionManager_deleteMembers(UA_SessionManager *sm) { + session_list_entry *current, *temp; + LIST_FOREACH_SAFE(current, &sm->sessions, pointers, temp) { + removeSession(sm, current); + } +} + +void +UA_SessionManager_cleanupTimedOut(UA_SessionManager *sm, + UA_DateTime nowMonotonic) { + session_list_entry *sentry, *temp; + LIST_FOREACH_SAFE(sentry, &sm->sessions, pointers, temp) { + /* Session has timed out? */ + if(sentry->session.validTill >= nowMonotonic) + continue; + UA_LOG_INFO_SESSION(sm->server->config.logger, &sentry->session, + "Session has timed out"); + sm->server->config.accessControl.closeSession(sm->server, + &sm->server->config.accessControl, + &sentry->session.sessionId, + sentry->session.sessionHandle); + removeSession(sm, sentry); + } +} + +UA_Session * +UA_SessionManager_getSessionByToken(UA_SessionManager *sm, const UA_NodeId *token) { + session_list_entry *current = NULL; + LIST_FOREACH(current, &sm->sessions, pointers) { + /* Token does not match */ + if(!UA_NodeId_equal(¤t->session.header.authenticationToken, token)) + continue; + + /* Session has timed out */ + if(UA_DateTime_nowMonotonic() > current->session.validTill) { + UA_LOG_INFO_SESSION(sm->server->config.logger, ¤t->session, + "Client tries to use a session that has timed out"); + return NULL; + } + + /* Ok, return */ + return ¤t->session; + } + + /* Session not found */ + UA_LOG_INFO(sm->server->config.logger, UA_LOGCATEGORY_SESSION, + "Try to use Session with token " UA_PRINTF_GUID_FORMAT " but is not found", + UA_PRINTF_GUID_DATA(token->identifier.guid)); + return NULL; +} + +UA_Session * +UA_SessionManager_getSessionById(UA_SessionManager *sm, const UA_NodeId *sessionId) { + session_list_entry *current = NULL; + LIST_FOREACH(current, &sm->sessions, pointers) { + /* Token does not match */ + if(!UA_NodeId_equal(¤t->session.sessionId, sessionId)) + continue; + + /* Session has timed out */ + if(UA_DateTime_nowMonotonic() > current->session.validTill) { + UA_LOG_INFO_SESSION(sm->server->config.logger, ¤t->session, + "Client tries to use a session that has timed out"); + return NULL; + } + + /* Ok, return */ + return ¤t->session; + } + + /* Session not found */ + UA_LOG_INFO(sm->server->config.logger, UA_LOGCATEGORY_SESSION, + "Try to use Session with identifier " UA_PRINTF_GUID_FORMAT " but is not found", + UA_PRINTF_GUID_DATA(sessionId->identifier.guid)); + return NULL; +} + +/* Creates and adds a session. But it is not yet attached to a secure channel. */ +UA_StatusCode +UA_SessionManager_createSession(UA_SessionManager *sm, UA_SecureChannel *channel, + const UA_CreateSessionRequest *request, UA_Session **session) { + if(sm->currentSessionCount >= sm->server->config.maxSessions) + return UA_STATUSCODE_BADTOOMANYSESSIONS; + + session_list_entry *newentry = (session_list_entry *)UA_malloc(sizeof(session_list_entry)); + if(!newentry) + return UA_STATUSCODE_BADOUTOFMEMORY; + + UA_atomic_addUInt32(&sm->currentSessionCount, 1); + 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()); + + if(request->requestedSessionTimeout <= sm->server->config.maxSessionTimeout && + request->requestedSessionTimeout > 0) + newentry->session.timeout = request->requestedSessionTimeout; + else + newentry->session.timeout = sm->server->config.maxSessionTimeout; + + UA_Session_updateLifetime(&newentry->session); + LIST_INSERT_HEAD(&sm->sessions, newentry, pointers); + *session = &newentry->session; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_SessionManager_removeSession(UA_SessionManager *sm, const UA_NodeId *token) { + session_list_entry *current; + LIST_FOREACH(current, &sm->sessions, pointers) { + if(UA_NodeId_equal(¤t->session.header.authenticationToken, token)) + break; + } + if(!current) + return UA_STATUSCODE_BADSESSIONIDINVALID; + return removeSession(sm, current); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2015-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2015 (c) Joakim L. Gilje + * Copyright 2016-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mattias Bornhager + * Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang) + */ + + +#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ + +UA_Subscription * +UA_Subscription_new(UA_Session *session, UA_UInt32 subscriptionId) { + /* Allocate the memory */ + 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 */ + /* 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) { + Subscription_unregisterPublishCallback(server, sub); + + /* Delete monitored Items */ + UA_MonitoredItem *mon, *tmp_mon; + LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, tmp_mon) { + UA_LOG_INFO_SESSION(server->config.logger, sub->session, + "Subscription %u | MonitoredItem %i | " + "Deleted the MonitoredItem", sub->subscriptionId, + mon->monitoredItemId); + MonitoredItem_delete(server, mon); + } + sub->monitoredItemsSize = 0; + + /* Delete Retransmission Queue */ + UA_NotificationMessageEntry *nme, *nme_tmp; + TAILQ_FOREACH_SAFE(nme, &sub->retransmissionQueue, listEntry, nme_tmp) { + TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry); + UA_NotificationMessage_deleteMembers(&nme->message); + UA_free(nme); + --sub->session->totalRetransmissionQueueSize; + --sub->retransmissionQueueSize; + } + UA_assert(sub->retransmissionQueueSize == 0); + + UA_LOG_INFO_SESSION(server->config.logger, sub->session, + "Subscription %u | Deleted the Subscription", + sub->subscriptionId); +} + +UA_MonitoredItem * +UA_Subscription_getMonitoredItem(UA_Subscription *sub, UA_UInt32 monitoredItemId) { + UA_MonitoredItem *mon; + LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { + if(mon->monitoredItemId == monitoredItemId) + break; + } + return mon; +} + +UA_StatusCode +UA_Subscription_deleteMonitoredItem(UA_Server *server, UA_Subscription *sub, + UA_UInt32 monitoredItemId) { + /* 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 %u | MonitoredItem %i | " + "Delete the MonitoredItem", sub->subscriptionId, + mon->monitoredItemId); + + /* Remove the MonitoredItem */ + MonitoredItem_delete(server, mon); + sub->monitoredItemsSize--; + return UA_STATUSCODE_GOOD; +} + +void +UA_Subscription_addMonitoredItem(UA_Subscription *sub, UA_MonitoredItem *newMon) { + sub->monitoredItemsSize++; + LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry); +} + +static void +removeOldestRetransmissionMessage(UA_Session *session) { + UA_NotificationMessageEntry *oldestEntry = NULL; + UA_Subscription *oldestSub = NULL; + + UA_Subscription *sub; + LIST_FOREACH(sub, &session->serverSubscriptions, listEntry) { + UA_NotificationMessageEntry *first = + TAILQ_LAST(&sub->retransmissionQueue, ListOfNotificationMessages); + if(!first) + continue; + if(!oldestEntry || oldestEntry->message.publishTime > first->message.publishTime) { + oldestEntry = first; + oldestSub = sub; + } + } + UA_assert(oldestEntry); + UA_assert(oldestSub); + + TAILQ_REMOVE(&oldestSub->retransmissionQueue, oldestEntry, listEntry); + UA_NotificationMessage_deleteMembers(&oldestEntry->message); + UA_free(oldestEntry); + --session->totalRetransmissionQueueSize; + --oldestSub->retransmissionQueueSize; +} + +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 %u | " + "Retransmission queue overflow", sub->subscriptionId); + removeOldestRetransmissionMessage(sub->session); + } + + /* Add entry */ + TAILQ_INSERT_TAIL(&sub->retransmissionQueue, entry, listEntry); + ++sub->session->totalRetransmissionQueueSize; + ++sub->retransmissionQueueSize; +} + +UA_StatusCode +UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub, UA_UInt32 sequenceNumber) { + /* Find the retransmission message */ + UA_NotificationMessageEntry *entry; + TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) { + if(entry->message.sequenceNumber == sequenceNumber) + break; + } + if(!entry) + return UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN; + + /* Remove the retransmission message */ + TAILQ_REMOVE(&sub->retransmissionQueue, entry, listEntry); + --sub->session->totalRetransmissionQueueSize; + --sub->retransmissionQueueSize; + UA_NotificationMessage_deleteMembers(&entry->message); + UA_free(entry); + return UA_STATUSCODE_GOOD; +} + +/* Iterate over the monitoreditems of the subscription, starting at mon, and + * move notifications into the response. */ +static void +moveNotificationsFromMonitoredItems(UA_Subscription *sub, UA_MonitoredItemNotification *mins, + size_t minsSize) { + size_t pos = 0; + UA_Notification *notification, *notification_tmp; + TAILQ_FOREACH_SAFE(notification, &sub->notificationQueue, globalEntry, notification_tmp) { + if(pos >= minsSize) + return; + + UA_MonitoredItem *mon = notification->mon; + + /* Remove the notification from the queues */ + TAILQ_REMOVE(&sub->notificationQueue, notification, globalEntry); + TAILQ_REMOVE(&mon->queue, notification, listEntry); + --mon->queueSize; + --sub->notificationQueueSize; + + /* Move the content to the response */ + UA_MonitoredItemNotification *min = &mins[pos]; + min->clientHandle = mon->clientHandle; + if(mon->monitoredItemType == UA_MONITOREDITEMTYPE_CHANGENOTIFY) { + min->value = notification->data.value; + } else { + /* TODO implementation for events */ + } + UA_free(notification); + ++pos; + } +} + +static UA_StatusCode +prepareNotificationMessage(UA_Subscription *sub, UA_NotificationMessage *message, + size_t notifications) { + /* Array of ExtensionObject to hold different kinds of notifications + * (currently only DataChangeNotifications) */ + message->notificationData = UA_ExtensionObject_new(); + if(!message->notificationData) + return UA_STATUSCODE_BADOUTOFMEMORY; + message->notificationDataSize = 1; + + /* Allocate Notification */ + UA_DataChangeNotification *dcn = UA_DataChangeNotification_new(); + if(!dcn) { + UA_NotificationMessage_deleteMembers(message); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + UA_ExtensionObject *data = message->notificationData; + data->encoding = UA_EXTENSIONOBJECT_DECODED; + data->content.decoded.data = dcn; + data->content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]; + + /* Allocate array of notifications */ + dcn->monitoredItems = (UA_MonitoredItemNotification *) + UA_Array_new(notifications, + &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]); + if(!dcn->monitoredItems) { + UA_NotificationMessage_deleteMembers(message); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + dcn->monitoredItemsSize = notifications; + + /* Move notifications into the response .. the point of no return */ + + moveNotificationsFromMonitoredItems(sub, dcn->monitoredItems, notifications); + + return UA_STATUSCODE_GOOD; +} + +/* According to OPC Unified Architecture, Part 4 5.13.1.1 i) The value 0 is + * never used for the sequence number */ +static UA_UInt32 +UA_Subscription_nextSequenceNumber(UA_UInt32 sequenceNumber) { + UA_UInt32 nextSequenceNumber = sequenceNumber + 1; + if(nextSequenceNumber == 0) + nextSequenceNumber = 1; + return nextSequenceNumber; +} + +static void +publishCallback(UA_Server *server, UA_Subscription *sub) { + sub->readyNotifications = sub->notificationQueueSize; + UA_Subscription_publish(server, sub); +} + +void +UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, "Subscription %u | " + "Publish Callback", sub->subscriptionId); + /* Dequeue a response */ + UA_PublishResponseEntry *pre = UA_Session_dequeuePublishReq(sub->session); + if(pre) { + sub->currentLifetimeCount = 0; /* Reset the LifetimeCounter */ + } else { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | The publish queue is empty", + sub->subscriptionId); + ++sub->currentLifetimeCount; + + if(sub->currentLifetimeCount > sub->lifeTimeCount) { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | End of lifetime " + "for subscription", sub->subscriptionId); + UA_Session_deleteSubscription(server, sub->session, sub->subscriptionId); + /* TODO: send a StatusChangeNotification with Bad_Timeout */ + return; + } + } + + if (sub->readyNotifications > sub->notificationQueueSize) + sub->readyNotifications = sub->notificationQueueSize; + + /* Count the available notifications */ + UA_UInt32 notifications = sub->readyNotifications; + if(!sub->publishingEnabled) + notifications = 0; + + UA_Boolean moreNotifications = false; + if(notifications > sub->notificationsPerPublish) { + notifications = sub->notificationsPerPublish; + moreNotifications = true; + } + + /* Return if no notifications and no keepalive */ + if(notifications == 0) { + ++sub->currentKeepAliveCount; + if(sub->currentKeepAliveCount < sub->maxKeepAliveCount) { + if(pre) + UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ + return; + } + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | Sending a KeepAlive", + sub->subscriptionId); + } + + /* We want to send a response. Is it possible? */ + UA_SecureChannel *channel = sub->session->header.channel; + if(!channel || !pre) { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | Want to send a publish response but can't. " + "The subscription is late.", sub->subscriptionId); + sub->state = UA_SUBSCRIPTIONSTATE_LATE; + if(pre) + UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ + return; + } + + /* Prepare the response */ + UA_PublishResponse *response = &pre->response; + UA_NotificationMessage *message = &response->notificationMessage; + UA_NotificationMessageEntry *retransmission = NULL; + if(notifications > 0) { + /* Allocate the retransmission entry */ + retransmission = (UA_NotificationMessageEntry*)UA_malloc(sizeof(UA_NotificationMessageEntry)); + if(!retransmission) { + UA_LOG_WARNING_SESSION(server->config.logger, sub->session, + "Subscription %u | Could not allocate memory for retransmission. " + "The subscription is late.", sub->subscriptionId); + sub->state = UA_SUBSCRIPTIONSTATE_LATE; + UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ + return; + } + + /* Prepare the response */ + UA_StatusCode retval = prepareNotificationMessage(sub, message, notifications); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(server->config.logger, sub->session, + "Subscription %u | Could not prepare the notification message. " + "The subscription is late.", sub->subscriptionId); + UA_free(retransmission); + sub->state = UA_SUBSCRIPTIONSTATE_LATE; + UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */ + return; + } + } + + /* <-- The point of no return --> */ + + /* Adjust the number of ready notifications */ + UA_assert(sub->readyNotifications >= notifications); + sub->readyNotifications -= notifications; + + /* Set up the response */ + response->responseHeader.timestamp = UA_DateTime_now(); + response->subscriptionId = sub->subscriptionId; + 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. */ + message->sequenceNumber = sub->nextSequenceNumber; + + if(notifications > 0) { + /* 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. */ + 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); + } + + /* 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; + } + } + + /* Send the response */ + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | Sending out a publish response " + "with %u notifications", sub->subscriptionId, + (UA_UInt32)notifications); + UA_SecureChannel_sendSymmetricMessage(sub->session->header.channel, pre->requestId, + UA_MESSAGETYPE_MSG, response, + &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + + /* Reset subscription state to normal */ + sub->state = UA_SUBSCRIPTIONSTATE_NORMAL; + sub->currentKeepAliveCount = 0; + + /* Free the response */ + UA_Array_delete(response->results, response->resultsSize, &UA_TYPES[UA_TYPES_UINT32]); + UA_free(pre); /* No need for UA_PublishResponse_deleteMembers */ + + /* 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_LOG_DEBUG_SESSION(server->config.logger, session, "Reached number of publish request limit"); + + /* Dequeue a response */ + UA_PublishResponseEntry *pre = UA_Session_dequeuePublishReq(session); + + /* Cannot publish without a response */ + if(!pre) { + UA_LOG_FATAL_SESSION(server->config.logger, session, "No publish requests available"); + return false; + } + + /* <-- The point of no return --> */ + + UA_PublishResponse *response = &pre->response; + UA_NotificationMessage *message = &response->notificationMessage; + + /* Set up the response. Note that this response has no related subscription id */ + response->responseHeader.timestamp = UA_DateTime_now(); + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS; + response->subscriptionId = 0; + response->moreNotifications = false; + message->publishTime = response->responseHeader.timestamp; + message->sequenceNumber = 0; + response->availableSequenceNumbersSize = 0; + + /* Send the response */ + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Sending out a publish response triggered by too many publish requests"); + UA_SecureChannel_sendSymmetricMessage(session->header.channel, pre->requestId, + UA_MESSAGETYPE_MSG, response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + + /* Free the response */ + UA_Array_delete(response->results, response->resultsSize, &UA_TYPES[UA_TYPES_UINT32]); + UA_free(pre); /* no need for UA_PublishResponse_deleteMembers */ + + return true; +} + +UA_StatusCode +Subscription_registerPublishCallback(UA_Server *server, UA_Subscription *sub) { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | Register subscription " + "publishing callback", sub->subscriptionId); + + if(sub->publishCallbackIsRegistered) + return UA_STATUSCODE_GOOD; + + UA_StatusCode retval = + UA_Server_addRepeatedCallback(server, (UA_ServerCallback)publishCallback, + sub, (UA_UInt32)sub->publishingInterval, &sub->publishCallbackId); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + sub->publishCallbackIsRegistered = true; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +Subscription_unregisterPublishCallback(UA_Server *server, UA_Subscription *sub) { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, "Subscription %u | " + "Unregister subscription publishing callback", sub->subscriptionId); + + if(!sub->publishCallbackIsRegistered) + return UA_STATUSCODE_GOOD; + + UA_StatusCode retval = UA_Server_removeRepeatedCallback(server, sub->publishCallbackId); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + sub->publishCallbackIsRegistered = false; + return UA_STATUSCODE_GOOD; +} + +/* 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(); + UA_SecureChannel_sendSymmetricMessage(session->header.channel, pre->requestId, UA_MESSAGETYPE_MSG, + response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + UA_PublishResponse_deleteMembers(response); + UA_free(pre); + } +} + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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/. + * + * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA + */ + + +#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ + +#define UA_VALUENCODING_MAXSTACK 512 + +UA_MonitoredItem * +UA_MonitoredItem_new(UA_MonitoredItemType monType) { + /* Allocate the memory */ + UA_MonitoredItem *newItem = + (UA_MonitoredItem *) UA_calloc(1, sizeof(UA_MonitoredItem)); + if(!newItem) + return NULL; + + /* Remaining members are covered by calloc zeroing out the memory */ + newItem->monitoredItemType = monType; /* currently hardcoded */ + newItem->timestampsToReturn = UA_TIMESTAMPSTORETURN_SOURCE; + TAILQ_INIT(&newItem->queue); + return newItem; +} + +void +MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem) { + UA_Subscription *sub = monitoredItem->subscription; + + if(monitoredItem->monitoredItemType == UA_MONITOREDITEMTYPE_CHANGENOTIFY) { + /* Remove the sampling callback */ + MonitoredItem_unregisterSampleCallback(server, monitoredItem); + + /* Clear the queued notifications */ + UA_Notification *notification, *notification_tmp; + TAILQ_FOREACH_SAFE(notification, &monitoredItem->queue, listEntry, notification_tmp) { + /* Remove the item from the queues */ + TAILQ_REMOVE(&monitoredItem->queue, notification, listEntry); + TAILQ_REMOVE(&sub->notificationQueue, notification, globalEntry); + --sub->notificationQueueSize; + + UA_DataValue_deleteMembers(¬ification->data.value); + UA_free(notification); + } + monitoredItem->queueSize = 0; + } else { + /* TODO: Access val data.event */ + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "MonitoredItemTypes other than ChangeNotify are not supported yet"); + } + + /* Remove the monitored item */ + if(monitoredItem->listEntry.le_prev != NULL) + LIST_REMOVE(monitoredItem, listEntry); + UA_String_deleteMembers(&monitoredItem->indexRange); + UA_ByteString_deleteMembers(&monitoredItem->lastSampledValue); + UA_Variant_deleteMembers(&monitoredItem->lastValue); + UA_NodeId_deleteMembers(&monitoredItem->monitoredNodeId); + UA_Server_delayedFree(server, monitoredItem); +} + +void MonitoredItem_ensureQueueSpace(UA_MonitoredItem *mon) { + if(mon->queueSize <= mon->maxQueueSize) + return; + + /* Remove notifications until the queue size is reached */ + UA_Subscription *sub = mon->subscription; + while(mon->queueSize > mon->maxQueueSize) { + UA_assert(mon->queueSize >= 2); /* At least two Notifications in the queue */ + + /* Make sure that the MonitoredItem does not lose its place in the + * global queue when notifications are removed. Otherwise the + * MonitoredItem can "starve" itself by putting new notifications always + * at the end of the global queue and removing the old ones. + * + * - If the oldest notification is removed, put the second oldest + * notification right behind it. + * - If the newest notification is removed, put the new notification + * right behind it. */ + + UA_Notification *del; /* The notification that will be deleted */ + UA_Notification *after_del; /* The notification to keep and move after del */ + if(mon->discardOldest) { + /* Remove the oldest */ + del = TAILQ_FIRST(&mon->queue); + after_del = TAILQ_NEXT(del, listEntry); + } else { + /* Remove the second newest (to keep the up-to-date notification) */ + after_del = TAILQ_LAST(&mon->queue, NotificationQueue); + del = TAILQ_PREV(after_del, NotificationQueue, listEntry); + } + + /* Move after_del right after del in the global queue */ + TAILQ_REMOVE(&sub->notificationQueue, after_del, globalEntry); + TAILQ_INSERT_AFTER(&sub->notificationQueue, del, after_del, globalEntry); + + /* Remove the notification from the queues */ + TAILQ_REMOVE(&mon->queue, del, listEntry); + TAILQ_REMOVE(&sub->notificationQueue, del, globalEntry); + --mon->queueSize; + --sub->notificationQueueSize; + + /* Free the notification */ + if(mon->monitoredItemType == UA_MONITOREDITEMTYPE_CHANGENOTIFY) { + UA_DataValue_deleteMembers(&del->data.value); + } else { + /* TODO: event implemantation */ + } + + /* Work around a false positive in clang analyzer */ +#ifndef __clang_analyzer__ + UA_free(del); +#endif + } + + if(mon->monitoredItemType == UA_MONITOREDITEMTYPE_CHANGENOTIFY) { + /* Get the element that carries the infobits */ + UA_Notification *notification = NULL; + if(mon->discardOldest) + notification = TAILQ_FIRST(&mon->queue); + else + notification = TAILQ_LAST(&mon->queue, NotificationQueue); + UA_assert(notification); + + if(mon->maxQueueSize > 1) { + /* Add the infobits either to the newest or the new last entry */ + notification->data.value.hasStatus = true; + notification->data.value.status |= (UA_STATUSCODE_INFOTYPE_DATAVALUE | + UA_STATUSCODE_INFOBITS_OVERFLOW); + } else { + /* If the queue size is reduced to one, remove the infobits */ + notification->data.value.status &= ~(UA_StatusCode)(UA_STATUSCODE_INFOTYPE_DATAVALUE | + UA_STATUSCODE_INFOBITS_OVERFLOW); + } + } + + /* TODO: Infobits for Events? */ +} + +#define ABS_SUBTRACT_TYPE_INDEPENDENT(a,b) ((a)>(b)?(a)-(b):(b)-(a)) + +static UA_INLINE UA_Boolean +outOfDeadBand(const void *data1, const void *data2, const size_t index, const UA_DataType *type, const UA_Double deadbandValue) { + if(type == &UA_TYPES[UA_TYPES_BOOLEAN]) { + if(ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Boolean*)data1)[index], ((const UA_Boolean*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_SBYTE]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_SByte*)data1)[index], ((const UA_SByte*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_BYTE]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Byte*)data1)[index], ((const UA_Byte*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_INT16]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Int16*)data1)[index], ((const UA_Int16*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_UINT16]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_UInt16*)data1)[index], ((const UA_UInt16*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_INT32]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Int32*)data1)[index], ((const UA_Int32*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_UINT32]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_UInt32*)data1)[index], ((const UA_UInt32*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_INT64]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Int64*)data1)[index], ((const UA_Int64*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_UINT64]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_UInt64*)data1)[index], ((const UA_UInt64*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_FLOAT]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Float*)data1)[index], ((const UA_Float*)data2)[index]) <= deadbandValue) + return false; + } else + if (type == &UA_TYPES[UA_TYPES_DOUBLE]) { + if (ABS_SUBTRACT_TYPE_INDEPENDENT(((const UA_Double*)data1)[index], ((const UA_Double*)data2)[index]) <= deadbandValue) + return false; + } + return true; +} + +static UA_INLINE UA_Boolean +updateNeededForFilteredValue(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; + } + if (UA_Variant_isScalar(value)) { + return outOfDeadBand(value->data, oldValue->data, 0, value->type, deadbandValue); + } else { + for (size_t i = 0; i < value->arrayLength; ++i) { + if (outOfDeadBand(value->data, oldValue->data, i, value->type, deadbandValue)) + return true; + } + } + return false; +} + +/* Errors are returned as no change detected */ +static UA_Boolean +detectValueChangeWithFilter(UA_MonitoredItem *mon, UA_DataValue *value, + UA_ByteString *encoding) { + if (isDataTypeNumeric(value->value.type) + && (mon->filter.trigger == UA_DATACHANGETRIGGER_STATUSVALUE + || mon->filter.trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP)) { + if (mon->filter.deadbandType == UA_DEADBANDTYPE_ABSOLUTE) { + if (!updateNeededForFilteredValue(&value->value, &mon->lastValue, mon->filter.deadbandValue)) + return false; + } /*else if (mon->filter.deadbandType == UA_DEADBANDTYPE_PERCENT) { + // TODO where do this EURange come from ? + UA_Double deadbandValue = fabs(mon->filter.deadbandValue * (EURange.high-EURange.low)); + if (!updateNeededForFilteredValue(value->value, mon->lastValue, deadbandValue)) + return false; + }*/ + } + + /* Encode the data for comparison */ + size_t binsize = UA_calcSizeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE]); + if(binsize == 0) + return false; + + /* Allocate buffer on the heap if necessary */ + if(binsize > UA_VALUENCODING_MAXSTACK && + UA_ByteString_allocBuffer(encoding, binsize) != UA_STATUSCODE_GOOD) + return false; + + /* Encode the value */ + UA_Byte *bufPos = encoding->data; + const UA_Byte *bufEnd = &encoding->data[encoding->length]; + UA_StatusCode retval = UA_encodeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE], + &bufPos, &bufEnd, NULL, NULL); + if(retval != UA_STATUSCODE_GOOD) + return false; + + /* The value has changed */ + encoding->length = (uintptr_t)bufPos - (uintptr_t)encoding->data; + return !mon->lastSampledValue.data || !UA_String_equal(encoding, &mon->lastSampledValue); +} + +/* 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_Boolean +detectValueChange(UA_MonitoredItem *mon, UA_DataValue *value, UA_ByteString *encoding) { + /* Apply Filter */ + UA_Boolean hasValue = value->hasValue; + if(mon->filter.trigger == UA_DATACHANGETRIGGER_STATUS) + value->hasValue = false; + + UA_Boolean hasServerTimestamp = value->hasServerTimestamp; + UA_Boolean hasServerPicoseconds = value->hasServerPicoseconds; + value->hasServerTimestamp = false; + value->hasServerPicoseconds = false; + + UA_Boolean hasSourceTimestamp = value->hasSourceTimestamp; + UA_Boolean hasSourcePicoseconds = value->hasSourcePicoseconds; + if(mon->filter.trigger < UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP) { + value->hasSourceTimestamp = false; + value->hasSourcePicoseconds = false; + } + + /* Detect the Value Change */ + UA_Boolean res = detectValueChangeWithFilter(mon, value, encoding); + + /* Reset the filter */ + value->hasValue = hasValue; + value->hasServerTimestamp = hasServerTimestamp; + value->hasServerPicoseconds = hasServerPicoseconds; + value->hasSourceTimestamp = hasSourceTimestamp; + value->hasSourcePicoseconds = hasSourcePicoseconds; + return res; +} + +/* Returns whether a new sample was created */ +static UA_Boolean +sampleCallbackWithValue(UA_Server *server, UA_Subscription *sub, + UA_MonitoredItem *monitoredItem, + UA_DataValue *value, + UA_ByteString *valueEncoding) { + UA_assert(monitoredItem->monitoredItemType == UA_MONITOREDITEMTYPE_CHANGENOTIFY); + /* Store the pointer to the stack-allocated bytestring to see if a heap-allocation + * was necessary */ + UA_Byte *stackValueEncoding = valueEncoding->data; + + /* Has the value changed? */ + UA_Boolean changed = detectValueChange(monitoredItem, value, valueEncoding); + if(!changed) + return false; + + /* Allocate the entry for the publish queue */ + UA_Notification *newNotification = + (UA_Notification *)UA_malloc(sizeof(UA_Notification)); + if(!newNotification) { + UA_LOG_WARNING_SESSION(server->config.logger, sub->session, + "Subscription %u | MonitoredItem %i | " + "Item for the publishing queue could not be allocated", + sub->subscriptionId, monitoredItem->monitoredItemId); + return false; + } + + /* Copy valueEncoding on the heap for the next comparison (if not already done) */ + if(valueEncoding->data == stackValueEncoding) { + UA_ByteString cbs; + if(UA_ByteString_copy(valueEncoding, &cbs) != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(server->config.logger, sub->session, + "Subscription %u | MonitoredItem %i | " + "ByteString to compare values could not be created", + sub->subscriptionId, monitoredItem->monitoredItemId); + UA_free(newNotification); + return false; + } + *valueEncoding = cbs; + } + + /* Prepare the newQueueItem */ + if(value->hasValue && value->value.storageType == UA_VARIANT_DATA_NODELETE) { + /* Make a deep copy of the value */ + UA_StatusCode retval = UA_DataValue_copy(value, &newNotification->data.value); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_SESSION(server->config.logger, sub->session, + "Subscription %u | MonitoredItem %i | " + "Item for the publishing queue could not be prepared", + sub->subscriptionId, monitoredItem->monitoredItemId); + UA_free(newNotification); + return false; + } + } else { + newNotification->data.value = *value; /* Just copy the value and do not release it */ + } + + /* <-- Point of no return --> */ + + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | MonitoredItem %u | Sampled a new value", + sub->subscriptionId, monitoredItem->monitoredItemId); + + newNotification->mon = monitoredItem; + + /* Replace the encoding for comparison */ + UA_Variant_deleteMembers(&monitoredItem->lastValue); + UA_Variant_copy(&value->value, &monitoredItem->lastValue); + UA_ByteString_deleteMembers(&monitoredItem->lastSampledValue); + monitoredItem->lastSampledValue = *valueEncoding; + + /* Add the notification to the end of local and global queue */ + TAILQ_INSERT_TAIL(&monitoredItem->queue, newNotification, listEntry); + TAILQ_INSERT_TAIL(&sub->notificationQueue, newNotification, globalEntry); + ++monitoredItem->queueSize; + ++sub->notificationQueueSize; + + /* Remove some notifications if the queue is beyond maximum capacity */ + MonitoredItem_ensureQueueSpace(monitoredItem); + + return true; +} + +void +UA_MonitoredItem_SampleCallback(UA_Server *server, + UA_MonitoredItem *monitoredItem) { + UA_Subscription *sub = monitoredItem->subscription; + if(monitoredItem->monitoredItemType != UA_MONITOREDITEMTYPE_CHANGENOTIFY) { + UA_LOG_DEBUG_SESSION(server->config.logger, sub->session, + "Subscription %u | MonitoredItem %i | " + "Not a data change notification", + sub->subscriptionId, monitoredItem->monitoredItemId); + return; + } + + /* Read the value */ + UA_ReadValueId rvid; + UA_ReadValueId_init(&rvid); + rvid.nodeId = monitoredItem->monitoredNodeId; + rvid.attributeId = monitoredItem->attributeId; + rvid.indexRange = monitoredItem->indexRange; + UA_DataValue value = + UA_Server_readWithSession(server, sub->session, + &rvid, monitoredItem->timestampsToReturn); + + /* 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; + + /* Create a sample and compare with the last value */ + UA_Boolean newNotification = sampleCallbackWithValue(server, sub, monitoredItem, + &value, &valueEncoding); + + /* Clean up */ + if(!newNotification) { + if(valueEncoding.data != stackValueEncoding) + UA_ByteString_deleteMembers(&valueEncoding); + UA_DataValue_deleteMembers(&value); + } +} + +UA_StatusCode +MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon) { + if(mon->sampleCallbackIsRegistered) + return UA_STATUSCODE_GOOD; + UA_StatusCode retval = + UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_MonitoredItem_SampleCallback, + mon, (UA_UInt32)mon->samplingInterval, &mon->sampleCallbackId); + if(retval == UA_STATUSCODE_GOOD) + mon->sampleCallbackIsRegistered = true; + return retval; +} + +UA_StatusCode +MonitoredItem_unregisterSampleCallback(UA_Server *server, UA_MonitoredItem *mon) { + if(!mon->sampleCallbackIsRegistered) + return UA_STATUSCODE_GOOD; + mon->sampleCallbackIsRegistered = false; + return UA_Server_removeRepeatedCallback(server, mon->sampleCallbackId); +} + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) LEvertz + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015 (c) Ecosmos + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) Lorenz Haas + * Copyright 2017 (c) pschoppe + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017 (c) Henrik Norrman + */ + + +/* Target node on top of the stack */ +static UA_StatusCode +fillReferenceDescription(UA_Server *server, const UA_Node *curr, + const UA_NodeReferenceKind *ref, + UA_UInt32 mask, UA_ReferenceDescription *descr) { + UA_ReferenceDescription_init(descr); + UA_StatusCode retval = UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId); + if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID) + retval |= UA_NodeId_copy(&ref->referenceTypeId, &descr->referenceTypeId); + if(mask & UA_BROWSERESULTMASK_ISFORWARD) + descr->isForward = !ref->isInverse; + if(mask & UA_BROWSERESULTMASK_NODECLASS) + retval |= UA_NodeClass_copy(&curr->nodeClass, &descr->nodeClass); + if(mask & UA_BROWSERESULTMASK_BROWSENAME) + retval |= UA_QualifiedName_copy(&curr->browseName, &descr->browseName); + if(mask & UA_BROWSERESULTMASK_DISPLAYNAME) + retval |= UA_LocalizedText_copy(&curr->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(type) { + retval |= UA_NodeId_copy(&type->nodeId, &descr->typeDefinition.nodeId); + UA_Nodestore_release(server, type); + } + } + } + return retval; +} + +static void +removeCp(ContinuationPointEntry *cp, UA_Session* session) { + LIST_REMOVE(cp, pointers); + UA_ByteString_deleteMembers(&cp->identifier); + UA_BrowseDescription_deleteMembers(&cp->browseDescription); + UA_free(cp); + ++session->availableContinuationPoints; +} + +static UA_Boolean +relevantReference(UA_Server *server, UA_Boolean includeSubtypes, + const UA_NodeId *rootRef, const UA_NodeId *testRef) { + if(!includeSubtypes) + return UA_NodeId_equal(rootRef, testRef); + + const UA_NodeId hasSubType = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE); + return isNodeInTree(&server->config.nodestore, testRef, rootRef, &hasSubType, 1); +} + +/* Returns whether the node / continuationpoint is done */ +static UA_Boolean +browseReferences(UA_Server *server, const UA_Node *node, + ContinuationPointEntry *cp, UA_BrowseResult *result) { + UA_assert(cp != NULL); + const UA_BrowseDescription *descr = &cp->browseDescription; + + /* If the node has no references, just return */ + if(node->referencesSize == 0) { + result->referencesSize = 0; + return true; + } + + /* Follow all references? */ + UA_Boolean browseAll = UA_NodeId_isNull(&descr->referenceTypeId); + + /* How many references can we return at most? */ + size_t maxrefs = cp->maxReferences; + if(maxrefs == 0) { + if(server->config.maxReferencesPerNode != 0) { + maxrefs = server->config.maxReferencesPerNode; + } else { + maxrefs = UA_INT32_MAX; + } + } else { + if(server->config.maxReferencesPerNode != 0 && maxrefs > server->config.maxReferencesPerNode) { + maxrefs = server->config.maxReferencesPerNode; + } + } + + /* Allocate the results array */ + size_t refs_size = 2; /* True size of the array */ + result->references = (UA_ReferenceDescription*) + UA_Array_new(refs_size, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]); + if(!result->references) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + return false; + } + + size_t referenceKindIndex = cp->referenceKindIndex; + size_t targetIndex = cp->targetIndex; + + /* Loop over the node's references */ + for(; referenceKindIndex < node->referencesSize; ++referenceKindIndex) { + UA_NodeReferenceKind *rk = &node->references[referenceKindIndex]; + + /* Reference in the right direction? */ + if(rk->isInverse && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD) + continue; + if(!rk->isInverse && descr->browseDirection == UA_BROWSEDIRECTION_INVERSE) + continue; + + /* Is the reference part of the hierarchy of references we look for? */ + if(!browseAll && !relevantReference(server, descr->includeSubtypes, + &descr->referenceTypeId, &rk->referenceTypeId)) + continue; + + /* Loop over the targets */ + for(; targetIndex < rk->targetIdsSize; ++targetIndex) { + /* Get the node */ + const UA_Node *target = UA_Nodestore_get(server, &rk->targetIds[targetIndex].nodeId); + if(!target) + continue; + + /* Test if the node class matches */ + if(descr->nodeClassMask != 0 && (target->nodeClass & descr->nodeClassMask) == 0) { + UA_Nodestore_release(server, target); + continue; + } + + /* A match! Can we return it? */ + if(result->referencesSize >= maxrefs) { + /* There are references we could not return */ + cp->referenceKindIndex = referenceKindIndex; + cp->targetIndex = targetIndex; + UA_Nodestore_release(server, target); + return false; + } + + /* Make enough space in the array */ + if(result->referencesSize >= refs_size) { + refs_size *= 2; + if(refs_size > maxrefs) + refs_size = maxrefs; + UA_ReferenceDescription *rd = (UA_ReferenceDescription*) + UA_realloc(result->references, sizeof(UA_ReferenceDescription) * refs_size); + if(!rd) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + UA_Nodestore_release(server, target); + goto error_recovery; + } + result->references = rd; + } + + /* Copy the node description. Target is on top of the stack */ + result->statusCode = + fillReferenceDescription(server, target, rk, descr->resultMask, + &result->references[result->referencesSize]); + + UA_Nodestore_release(server, target); + + if(result->statusCode != UA_STATUSCODE_GOOD) + goto error_recovery; + + /* Increase the counter */ + result->referencesSize++; + } + + targetIndex = 0; /* Start at index 0 for the next reference kind */ + } + + /* No relevant references, return array of length zero */ + if(result->referencesSize == 0) { + UA_free(result->references); + result->references = (UA_ReferenceDescription*)UA_EMPTY_ARRAY_SENTINEL; + } + + /* The node is done */ + return true; + + error_recovery: + if(result->referencesSize == 0) + UA_free(result->references); + else + UA_Array_delete(result->references, result->referencesSize, + &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]); + result->references = NULL; + result->referencesSize = 0; + return false; +} + +/* Results for a single browsedescription. This is the inner loop for both + * Browse and BrowseNext. The ContinuationPoint contains all the data used. + * Including the BrowseDescription. Returns whether there are remaining + * references. */ +static UA_Boolean +browseWithContinuation(UA_Server *server, UA_Session *session, + ContinuationPointEntry *cp, UA_BrowseResult *result) { + const UA_BrowseDescription *descr = &cp->browseDescription; + + /* Is the browsedirection valid? */ + if(descr->browseDirection != UA_BROWSEDIRECTION_BOTH && + descr->browseDirection != UA_BROWSEDIRECTION_FORWARD && + descr->browseDirection != UA_BROWSEDIRECTION_INVERSE) { + result->statusCode = UA_STATUSCODE_BADBROWSEDIRECTIONINVALID; + return true; + } + + /* Is the reference type valid? */ + if(!UA_NodeId_isNull(&descr->referenceTypeId)) { + const UA_Node *reftype = UA_Nodestore_get(server, &descr->referenceTypeId); + if(!reftype) { + result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + return true; + } + + UA_Boolean isRef = (reftype->nodeClass == UA_NODECLASS_REFERENCETYPE); + UA_Nodestore_release(server, reftype); + + if(!isRef) { + result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + return true; + } + } + + const UA_Node *node = UA_Nodestore_get(server, &descr->nodeId); + if(!node) { + result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN; + return true; + } + + /* Browse the references */ + UA_Boolean done = browseReferences(server, node, cp, result); + UA_Nodestore_release(server, node); + return done; +} + +/* Start to browse with no previous cp */ +void +Operation_Browse(UA_Server *server, UA_Session *session, UA_UInt32 *maxrefs, + const UA_BrowseDescription *descr, UA_BrowseResult *result) { + /* Stack-allocate a temporary cp */ + UA_STACKARRAY(ContinuationPointEntry, cp, 1); + memset(cp, 0, sizeof(ContinuationPointEntry)); + cp->maxReferences = *maxrefs; + cp->browseDescription = *descr; /* Shallow copy. Deep-copy later if we persist the cp. */ + + UA_Boolean done = browseWithContinuation(server, session, cp, result); + + /* Exit early if done or an error occurred */ + if(done || result->statusCode != UA_STATUSCODE_GOOD) + return; + + /* Persist the new continuation point */ + ContinuationPointEntry *cp2 = NULL; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(session->availableContinuationPoints <= 0 || + !(cp2 = (ContinuationPointEntry *)UA_malloc(sizeof(ContinuationPointEntry)))) { + retval = UA_STATUSCODE_BADNOCONTINUATIONPOINTS; + goto cleanup; + } + memset(cp2, 0, sizeof(ContinuationPointEntry)); + cp2->referenceKindIndex = cp->referenceKindIndex; + cp2->targetIndex = cp->targetIndex; + cp2->maxReferences = cp->maxReferences; + retval = UA_BrowseDescription_copy(descr, &cp2->browseDescription); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Create a random bytestring via a Guid */ + UA_Guid *ident = UA_Guid_new(); + if(!ident) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } + *ident = UA_Guid_random(); + cp2->identifier.data = (UA_Byte*)ident; + cp2->identifier.length = sizeof(UA_Guid); + + /* Return the cp identifier */ + retval = UA_ByteString_copy(&cp2->identifier, &result->continuationPoint); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Attach the cp to the session */ + LIST_INSERT_HEAD(&session->continuationPoints, cp2, pointers); + --session->availableContinuationPoints; + return; + + cleanup: + if(cp2) { + UA_ByteString_deleteMembers(&cp2->identifier); + UA_BrowseDescription_deleteMembers(&cp2->browseDescription); + UA_free(cp2); + } + UA_BrowseResult_deleteMembers(result); + result->statusCode = retval; +} + +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"); + + if(server->config.maxNodesPerBrowse != 0 && + request->nodesToBrowseSize > server->config.maxNodesPerBrowse) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + /* No views supported at the moment */ + if(!UA_NodeId_isNull(&request->view.viewId)) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADVIEWIDUNKNOWN; + return; + } + + UA_UInt32 requestedMaxReferencesPerNode = request->requestedMaxReferencesPerNode; + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_Browse, + &requestedMaxReferencesPerNode, + &request->nodesToBrowseSize, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], + &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSERESULT]); +} + +UA_BrowseResult +UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs, const UA_BrowseDescription *descr) { + UA_BrowseResult result; + UA_BrowseResult_init(&result); + Operation_Browse(server, &server->adminSession, &maxrefs, descr, &result); + return result; +} + +static void +Operation_BrowseNext(UA_Server *server, UA_Session *session, UA_Boolean *releaseContinuationPoints, + const UA_ByteString *continuationPoint, UA_BrowseResult *result) { + /* Find the continuation point */ + ContinuationPointEntry *cp; + LIST_FOREACH(cp, &session->continuationPoints, pointers) { + if(UA_ByteString_equal(&cp->identifier, continuationPoint)) + break; + } + if(!cp) { + result->statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID; + return; + } + + /* Remove the cp */ + if(*releaseContinuationPoints) { + removeCp(cp, session); + return; + } + + /* Continue browsing */ + UA_Boolean done = browseWithContinuation(server, session, cp, result); + + if(done) { + /* Remove the cp if there are no references left */ + removeCp(cp, session); + } else { + /* Return the cp identifier */ + UA_StatusCode retval = UA_ByteString_copy(&cp->identifier, &result->continuationPoint); + if(retval != UA_STATUSCODE_GOOD) { + UA_BrowseResult_deleteMembers(result); + result->statusCode = retval; + } + } +} + +void +Service_BrowseNext(UA_Server *server, UA_Session *session, + const UA_BrowseNextRequest *request, + UA_BrowseNextResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing BrowseNextRequest"); + UA_Boolean releaseContinuationPoints = request->releaseContinuationPoints; /* request is const */ + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_BrowseNext, + &releaseContinuationPoints, + &request->continuationPointsSize, &UA_TYPES[UA_TYPES_BYTESTRING], + &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSERESULT]); +} + +UA_BrowseResult +UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, + const UA_ByteString *continuationPoint) { + UA_BrowseResult result; + UA_BrowseResult_init(&result); + Operation_BrowseNext(server, &server->adminSession, &releaseContinuationPoint, + continuationPoint, &result); + return result; +} + +/***********************/ +/* TranslateBrowsePath */ +/***********************/ + +static void +walkBrowsePathElementReferenceTargets(UA_BrowsePathResult *result, size_t *targetsSize, + UA_NodeId **next, size_t *nextSize, size_t *nextCount, + UA_UInt32 elemDepth, const UA_NodeReferenceKind *rk) { + /* Loop over the targets */ + for(size_t i = 0; i < rk->targetIdsSize; i++) { + UA_ExpandedNodeId *targetId = &rk->targetIds[i]; + + /* Does the reference point to an external server? Then add to the + * targets with the right path depth. */ + if(targetId->serverIndex != 0) { + UA_BrowsePathTarget *tempTargets = + (UA_BrowsePathTarget*)UA_realloc(result->targets, + sizeof(UA_BrowsePathTarget) * (*targetsSize) * 2); + if(!tempTargets) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + result->targets = tempTargets; + (*targetsSize) *= 2; + result->statusCode = UA_ExpandedNodeId_copy(targetId, + &result->targets[result->targetsSize].targetId); + result->targets[result->targetsSize].remainingPathIndex = elemDepth; + continue; + } + + /* Can we store the node in the array of candidates for deep-search? */ + if(*nextSize <= *nextCount) { + UA_NodeId *tempNext = + (UA_NodeId*)UA_realloc(*next, sizeof(UA_NodeId) * (*nextSize) * 2); + if(!tempNext) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + *next = tempNext; + (*nextSize) *= 2; + } + + /* Add the node to the next array for the following path element */ + result->statusCode = UA_NodeId_copy(&targetId->nodeId, + &(*next)[*nextCount]); + if(result->statusCode != UA_STATUSCODE_GOOD) + return; + ++(*nextCount); + } +} + +static void +walkBrowsePathElement(UA_Server *server, UA_Session *session, + UA_BrowsePathResult *result, size_t *targetsSize, + const UA_RelativePathElement *elem, UA_UInt32 elemDepth, + const UA_QualifiedName *targetName, + const UA_NodeId *current, const size_t currentCount, + UA_NodeId **next, size_t *nextSize, size_t *nextCount) { + /* Return all references? */ + 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_Boolean match = (rootRef->nodeClass == UA_NODECLASS_REFERENCETYPE); + UA_Nodestore_release(server, rootRef); + if(!match) + return; + } + + /* Iterate over all nodes at the current depth-level */ + for(size_t i = 0; i < currentCount; ++i) { + /* Get the node */ + const UA_Node *node = UA_Nodestore_get(server, ¤t[i]); + if(!node) { + /* If we cannot find the node at depth 0, the starting node does not exist */ + if(elemDepth == 0) + result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN; + continue; + } + + /* Test whether the current node has the target name required in the + * previous path element */ + if(targetName && (targetName->namespaceIndex != node->browseName.namespaceIndex || + !UA_String_equal(&targetName->name, &node->browseName.name))) { + UA_Nodestore_release(server, node); + continue; + } + + /* Loop over the nodes references */ + for(size_t r = 0; r < node->referencesSize && + result->statusCode == UA_STATUSCODE_GOOD; ++r) { + UA_NodeReferenceKind *rk = &node->references[r]; + + /* Does the direction of the reference match? */ + if(rk->isInverse != elem->isInverse) + continue; + + /* Is the node relevant? */ + if(!all_refs && !relevantReference(server, elem->includeSubtypes, + &elem->referenceTypeId, &rk->referenceTypeId)) + continue; + + /* Walk over the reference targets */ + walkBrowsePathElementReferenceTargets(result, targetsSize, next, nextSize, + nextCount, elemDepth, rk); + } + + UA_Nodestore_release(server, node); + } +} + +/* This assumes that result->targets has enough room for all currentCount elements */ +static void +addBrowsePathTargets(UA_Server *server, UA_Session *session, + UA_BrowsePathResult *result, const UA_QualifiedName *targetName, + UA_NodeId *current, size_t currentCount) { + for(size_t i = 0; i < currentCount; i++) { + const UA_Node *node = UA_Nodestore_get(server, ¤t[i]); + if(!node) { + UA_NodeId_deleteMembers(¤t[i]); + continue; + } + + /* Test whether the current node has the target name required in the + * previous path element */ + UA_Boolean valid = targetName->namespaceIndex == node->browseName.namespaceIndex && + UA_String_equal(&targetName->name, &node->browseName.name); + + UA_Nodestore_release(server, node); + + if(!valid) { + UA_NodeId_deleteMembers(¤t[i]); + continue; + } + + /* Move the nodeid to the target array */ + UA_BrowsePathTarget_init(&result->targets[result->targetsSize]); + result->targets[result->targetsSize].targetId.nodeId = current[i]; + result->targets[result->targetsSize].remainingPathIndex = UA_UINT32_MAX; + ++result->targetsSize; + } +} + +static void +walkBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path, + UA_BrowsePathResult *result, size_t targetsSize, + UA_NodeId **current, size_t *currentSize, size_t *currentCount, + UA_NodeId **next, size_t *nextSize, size_t *nextCount) { + UA_assert(*currentCount == 1); + UA_assert(*nextCount == 0); + + /* Points to the targetName of the _previous_ path element */ + const UA_QualifiedName *targetName = NULL; + + /* Iterate over path elements */ + UA_assert(path->relativePath.elementsSize > 0); + for(UA_UInt32 i = 0; i < path->relativePath.elementsSize; ++i) { + walkBrowsePathElement(server, session, result, &targetsSize, + &path->relativePath.elements[i], i, targetName, + *current, *currentCount, next, nextSize, nextCount); + + /* Clean members of current */ + for(size_t j = 0; j < *currentCount; j++) + UA_NodeId_deleteMembers(&(*current)[j]); + *currentCount = 0; + + /* When no targets are left or an error occurred. None of next's + * elements will be copied to result->targets */ + if(*nextCount == 0 || result->statusCode != UA_STATUSCODE_GOOD) { + UA_assert(*currentCount == 0); + UA_assert(*nextCount == 0); + return; + } + + /* Exchange current and next for the next depth */ + size_t tSize = *currentSize; size_t tCount = *currentCount; UA_NodeId *tT = *current; + *currentSize = *nextSize; *currentCount = *nextCount; *current = *next; + *nextSize = tSize; *nextCount = tCount; *next = tT; + + /* Store the target name of the previous path element */ + targetName = &path->relativePath.elements[i].targetName; + } + + UA_assert(targetName != NULL); + UA_assert(*nextCount == 0); + + /* After the last BrowsePathElement, move members from current to the + * result targets */ + + /* Realloc if more space is needed */ + if(targetsSize < result->targetsSize + (*currentCount)) { + UA_BrowsePathTarget *newTargets = + (UA_BrowsePathTarget*)UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) * + (result->targetsSize + (*currentCount))); + if(!newTargets) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + for(size_t i = 0; i < *currentCount; ++i) + UA_NodeId_deleteMembers(&(*current)[i]); + *currentCount = 0; + return; + } + result->targets = newTargets; + } + + /* Move the elements of current to the targets */ + addBrowsePathTargets(server, session, result, targetName, *current, *currentCount); + *currentCount = 0; +} + +static void +Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session, + void *context, const UA_BrowsePath *path, + UA_BrowsePathResult *result) { + if(path->relativePath.elementsSize <= 0) { + result->statusCode = UA_STATUSCODE_BADNOTHINGTODO; + return; + } + + /* RelativePath elements must not have an empty targetName */ + for(size_t i = 0; i < path->relativePath.elementsSize; ++i) { + if(UA_QualifiedName_isNull(&path->relativePath.elements[i].targetName)) { + result->statusCode = UA_STATUSCODE_BADBROWSENAMEINVALID; + return; + } + } + + /* Allocate memory for the targets */ + size_t targetsSize = 10; /* When to realloc; the member count is stored in + * result->targetsSize */ + result->targets = + (UA_BrowsePathTarget*)UA_malloc(sizeof(UA_BrowsePathTarget) * targetsSize); + if(!result->targets) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + /* Allocate memory for two temporary arrays. One with the results for the + * previous depth of the path. The other for the new results at the current + * depth. The two arrays alternate as we descend down the tree. */ + size_t currentSize = 10; /* When to realloc */ + size_t currentCount = 0; /* Current elements */ + UA_NodeId *current = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * currentSize); + if(!current) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + UA_free(result->targets); + return; + } + size_t nextSize = 10; /* When to realloc */ + size_t nextCount = 0; /* Current elements */ + UA_NodeId *next = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * nextSize); + if(!next) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + UA_free(result->targets); + UA_free(current); + return; + } + + /* Copy the starting node into current */ + result->statusCode = UA_NodeId_copy(&path->startingNode, ¤t[0]); + if(result->statusCode != UA_STATUSCODE_GOOD) { + UA_free(result->targets); + UA_free(current); + UA_free(next); + return; + } + currentCount = 1; + + /* Walk the path elements */ + walkBrowsePath(server, session, path, result, targetsSize, + ¤t, ¤tSize, ¤tCount, + &next, &nextSize, &nextCount); + + UA_assert(currentCount == 0); + UA_assert(nextCount == 0); + + /* No results => BadNoMatch status code */ + if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD) + result->statusCode = UA_STATUSCODE_BADNOMATCH; + + /* Clean up the temporary arrays and the targets */ + UA_free(current); + UA_free(next); + if(result->statusCode != UA_STATUSCODE_GOOD) { + for(size_t i = 0; i < result->targetsSize; ++i) + UA_BrowsePathTarget_deleteMembers(&result->targets[i]); + UA_free(result->targets); + result->targets = NULL; + result->targetsSize = 0; + } +} + +UA_BrowsePathResult +UA_Server_translateBrowsePathToNodeIds(UA_Server *server, + const UA_BrowsePath *browsePath) { + UA_BrowsePathResult result; + UA_BrowsePathResult_init(&result); + Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, NULL, browsePath, &result); + return result; +} + +void +Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session, + const UA_TranslateBrowsePathsToNodeIdsRequest *request, + UA_TranslateBrowsePathsToNodeIdsResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing TranslateBrowsePathsToNodeIdsRequest"); + + if(server->config.maxNodesPerTranslateBrowsePathsToNodeIds != 0 && + request->browsePathsSize > server->config.maxNodesPerTranslateBrowsePathsToNodeIds) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, + (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds, + NULL, &request->browsePathsSize, &UA_TYPES[UA_TYPES_BROWSEPATH], + &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]); +} + +void Service_RegisterNodes(UA_Server *server, UA_Session *session, + const UA_RegisterNodesRequest *request, + UA_RegisterNodesResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing RegisterNodesRequest"); + + //TODO: hang the nodeids to the session if really needed + if(request->nodesToRegisterSize == 0) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; + return; + } + + if(server->config.maxNodesPerRegisterNodes != 0 && + request->nodesToRegisterSize > server->config.maxNodesPerRegisterNodes) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + response->responseHeader.serviceResult = + UA_Array_copy(request->nodesToRegister, request->nodesToRegisterSize, + (void**)&response->registeredNodeIds, &UA_TYPES[UA_TYPES_NODEID]); + if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) + response->registeredNodeIdsSize = request->nodesToRegisterSize; +} + +void Service_UnregisterNodes(UA_Server *server, UA_Session *session, + const UA_UnregisterNodesRequest *request, + UA_UnregisterNodesResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing UnRegisterNodesRequest"); + + //TODO: remove the nodeids from the session if really needed + if(request->nodesToUnregisterSize == 0) + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; + + if(server->config.maxNodesPerRegisterNodes != 0 && + request->nodesToUnregisterSize > server->config.maxNodesPerRegisterNodes) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/server/ua_services_call.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 (c) Chris Iatrou + * Copyright 2015-2017 (c) Florian Palm + * Copyright 2015-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016 (c) LEvertz + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Julian Grothoff + */ + + +#ifdef UA_ENABLE_METHODCALLS /* conditional compilation */ + +static const UA_VariableNode * +getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod, + 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]; + + if(rk->isInverse != false) + continue; + + if(!UA_NodeId_equal(&hasProperty, &rk->referenceTypeId)) + continue; + + for(size_t j = 0; j < rk->targetIdsSize; ++j) { + const UA_Node *refTarget = + server->config.nodestore.getNode(server->config.nodestore.context, + &rk->targetIds[j].nodeId); + 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; + } + server->config.nodestore.releaseNode(server->config.nodestore.context, + refTarget); + } + } + return NULL; +} + +static UA_StatusCode +typeCheckArguments(UA_Server *server, UA_Session *session, + const UA_VariableNode *argRequirements, size_t argsSize, + UA_Variant *args, UA_StatusCode *inputArgumentResults) { + /* Verify that we have a Variant containing UA_Argument (scalar or array) in + * the "InputArguments" node */ + if(argRequirements->valueSource != UA_VALUESOURCE_DATA) + return UA_STATUSCODE_BADINTERNALERROR; + if(!argRequirements->value.data.value.hasValue) + return UA_STATUSCODE_BADINTERNALERROR; + if(argRequirements->value.data.value.value.type != &UA_TYPES[UA_TYPES_ARGUMENT]) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Verify the number of arguments. A scalar argument value is interpreted as + * an array of length 1. */ + size_t argReqsSize = argRequirements->value.data.value.value.arrayLength; + if(UA_Variant_isScalar(&argRequirements->value.data.value.value)) + argReqsSize = 1; + if(argReqsSize > argsSize) + return UA_STATUSCODE_BADARGUMENTSMISSING; + if(argReqsSize < argsSize) + return UA_STATUSCODE_BADTOOMANYARGUMENTS; + + /* Type-check every argument against the definition */ + UA_Argument *argReqs = (UA_Argument*)argRequirements->value.data.value.value.data; + 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)) + return UA_STATUSCODE_BADTYPEMISMATCH; + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +validMethodArguments(UA_Server *server, UA_Session *session, const UA_MethodNode *method, + const UA_CallMethodRequest *request, + UA_StatusCode *inputArgumentResults) { + /* Get the input arguments node */ + const UA_VariableNode *inputArguments = + getArgumentsVariableNode(server, method, UA_STRING("InputArguments")); + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(!inputArguments) { + if(request->inputArgumentsSize > 0) + retval = UA_STATUSCODE_BADINVALIDARGUMENT; + return retval; + } + + /* Verify the request */ + retval = typeCheckArguments(server, session, inputArguments, + request->inputArgumentsSize, + request->inputArguments, + inputArgumentResults); + + /* Release the input arguments node */ + server->config.nodestore.releaseNode(server->config.nodestore.context, + (const UA_Node*)inputArguments); + return retval; +} + +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 void +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) { + result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; + return; + } + + /* Verify the method's NodeClass */ + if(method->nodeClass != UA_NODECLASS_METHOD) { + result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; + return; + } + + /* Is there a method to execute? */ + if(!method->method) { + result->statusCode = UA_STATUSCODE_BADINTERNALERROR; + return; + } + + /* 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_Boolean found = false; + for(size_t i = 0; i < object->referencesSize && !found; ++i) { + UA_NodeReferenceKind *rk = &object->references[i]; + if(rk->isInverse) + continue; + if(!isNodeInTree(&server->config.nodestore, &rk->referenceTypeId, + &hasComponentNodeId, &hasSubTypeNodeId, 1)) + continue; + for(size_t j = 0; j < rk->targetIdsSize; ++j) { + if(UA_NodeId_equal(&rk->targetIds[j].nodeId, &request->methodId)) { + found = true; + break; + } + } + } + if(!found) { + result->statusCode = UA_STATUSCODE_BADMETHODINVALID; + return; + } + + /* Verify access rights */ + UA_Boolean executable = method->executable; + if(session != &server->adminSession) + executable = executable && + server->config.accessControl.getUserExecutableOnObject(server, + &server->config.accessControl, &session->sessionId, + session->sessionHandle, &request->methodId, method->context, + &request->objectId, object->context); + if(!executable) { + result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE? + return; + } + + /* Verify Input Arguments */ + result->statusCode = validMethodArguments(server, session, method, request, result->inputArgumentResults); + + /* Return inputArgumentResults only for BADINVALIDARGUMENT */ + if(result->statusCode != UA_STATUSCODE_BADINVALIDARGUMENT) { + UA_Array_delete(result->inputArgumentResults, result->inputArgumentResultsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); + result->inputArgumentResults = NULL; + result->inputArgumentResultsSize = 0; + } + + /* Error during type-checking? */ + if(result->statusCode != UA_STATUSCODE_GOOD) + return; + + /* Get the output arguments node */ + const UA_VariableNode *outputArguments = + getArgumentsVariableNode(server, method, UA_STRING("OutputArguments")); + + /* Allocate the output arguments array */ + if(outputArguments) { + if(outputArguments->value.data.value.value.arrayLength > 0) { + result->outputArguments = (UA_Variant*) + UA_Array_new(outputArguments->value.data.value.value.arrayLength, + &UA_TYPES[UA_TYPES_VARIANT]); + if(!result->outputArguments) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + result->outputArgumentsSize = outputArguments->value.data.value.value.arrayLength; + } + + /* Release the output arguments node */ + server->config.nodestore.releaseNode(server->config.nodestore.context, + (const UA_Node*)outputArguments); + } + + /* Call the method */ + result->statusCode = method->method(server, &session->sessionId, session->sessionHandle, + &method->nodeId, method->context, + &object->nodeId, object->context, + request->inputArgumentsSize, request->inputArguments, + result->outputArgumentsSize, result->outputArguments); + /* TODO: Verify Output matches the argument definition */ +} + +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*) + server->config.nodestore.getNode(server->config.nodestore.context, + &request->methodId); + if(!method) { + result->statusCode = UA_STATUSCODE_BADMETHODINVALID; + return; + } + + /* Get the object node */ + const UA_ObjectNode *object = (const UA_ObjectNode*) + server->config.nodestore.getNode(server->config.nodestore.context, + &request->objectId); + if(!object) { + result->statusCode = UA_STATUSCODE_BADNODEIDINVALID; + server->config.nodestore.releaseNode(server->config.nodestore.context, + (const UA_Node*)method); + return; + } + + /* Continue with method and object as context */ + callWithMethodAndObject(server, session, request, result, method, object); + + /* Release the method and object node */ + server->config.nodestore.releaseNode(server->config.nodestore.context, + (const UA_Node*)method); + server->config.nodestore.releaseNode(server->config.nodestore.context, + (const UA_Node*)object); +} + +void Service_Call(UA_Server *server, UA_Session *session, + const UA_CallRequest *request, + UA_CallResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing CallRequest"); + + if(server->config.maxNodesPerMethodCall != 0 && + request->methodsToCallSize > server->config.maxNodesPerMethodCall) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + 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_CallMethodResult UA_EXPORT +UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) { + UA_CallMethodResult result; + UA_CallMethodResult_init(&result); + Operation_CallMethod(server, &server->adminSession, NULL, request, &result); + return result; +} + +#endif /* UA_ENABLE_METHODCALLS */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2014-2016 (c) Sten Grüner + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB + */ + + +static UA_StatusCode +signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel, + const UA_CreateSessionRequest *request, + UA_CreateSessionResponse *response) { + if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && + channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + return UA_STATUSCODE_GOOD; + + const UA_SecurityPolicy *const securityPolicy = channel->securityPolicy; + UA_SignatureData *signatureData = &response->serverSignature; + + /* Prepare the signature */ + size_t signatureSize = securityPolicy->certificateSigningAlgorithm. + getLocalSignatureSize(securityPolicy, channel->channelContext); + UA_StatusCode retval = UA_String_copy(&securityPolicy->certificateSigningAlgorithm.uri, + &signatureData->algorithm); + retval |= UA_ByteString_allocBuffer(&signatureData->signature, signatureSize); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Allocate a temp buffer */ + size_t dataToSignSize = request->clientCertificate.length + request->clientNonce.length; + UA_ByteString dataToSign; + retval = UA_ByteString_allocBuffer(&dataToSign, dataToSignSize); + if(retval != UA_STATUSCODE_GOOD) + return retval; /* signatureData->signature is cleaned up with the response */ + + /* Sign the signature */ + memcpy(dataToSign.data, request->clientCertificate.data, request->clientCertificate.length); + memcpy(dataToSign.data + request->clientCertificate.length, + request->clientNonce.data, request->clientNonce.length); + retval = securityPolicy->certificateSigningAlgorithm. + sign(securityPolicy, channel->channelContext, &dataToSign, &signatureData->signature); + + /* Clean up */ + UA_ByteString_deleteMembers(&dataToSign); + return retval; +} + +void +Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, + const UA_CreateSessionRequest *request, + UA_CreateSessionResponse *response) { + if(!channel) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + return; + } + + if(!channel->connection) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + return; + } + + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Trying to create session"); + + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + /* Compare the clientCertificate with the remoteCertificate of the channel. + * Both the clientCertificate of this request and the remoteCertificate + * of the channel may contain a partial or a complete certificate chain. + * The compareCertificate function of the channelModule will compare the + * first certificate of each chain. The end certificate shall be located + * first in the chain according to the OPC UA specification Part 6 (1.04), + * chapter 6.2.3.*/ + if(channel->securityPolicy->channelModule.compareCertificate(channel->channelContext, + &request->clientCertificate) != UA_STATUSCODE_GOOD) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADCERTIFICATEINVALID; + return; + } + } + + if(channel->securityToken.channelId == 0) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID; + return; + } + + if(!UA_ByteString_equal(&channel->securityPolicy->policyUri, + &UA_SECURITY_POLICY_NONE_URI) && + request->clientNonce.length < 32) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADNONCEINVALID; + return; + } + + /* TODO: Compare application URI with certificate uri (decode certificate) */ + UA_CertificateVerification *cv = channel->securityPolicy->certificateVerification; + if(cv && cv->verifyApplicationURI) { + response->responseHeader.serviceResult = + cv->verifyApplicationURI(cv->context, &request->clientCertificate, + &request->clientDescription.applicationUri); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) + return; + } + + UA_Session *newSession = NULL; + response->responseHeader.serviceResult = + UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, + "Processing CreateSessionRequest failed"); + return; + } + + UA_assert(newSession != NULL); + + /* Allocate the response */ + response->serverEndpoints = (UA_EndpointDescription *) + UA_Array_new(server->config.endpointsSize, + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); + if(!response->serverEndpoints) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + UA_SessionManager_removeSession(&server->sessionManager, + &newSession->header.authenticationToken); + return; + } + response->serverEndpointsSize = server->config.endpointsSize; + + /* Copy the server's endpointdescriptions into the response */ + for(size_t i = 0; i < server->config.endpointsSize; ++i) + response->responseHeader.serviceResult |= + UA_EndpointDescription_copy(&server->config.endpoints[i].endpointDescription, + &response->serverEndpoints[i]); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_SessionManager_removeSession(&server->sessionManager, + &newSession->header.authenticationToken); + return; + } + + /* Mirror back the endpointUrl */ + for(size_t i = 0; i < response->serverEndpointsSize; ++i) { + UA_String_deleteMembers(&response->serverEndpoints[i].endpointUrl); + response->responseHeader.serviceResult |= + UA_String_copy(&request->endpointUrl, + &response->serverEndpoints[i].endpointUrl); + } + + /* Attach the session to the channel. But don't activate for now. */ + UA_Session_attachToSecureChannel(newSession, channel); + + /* Fill the session information */ + newSession->maxResponseMessageSize = request->maxResponseMessageSize; + newSession->maxRequestMessageSize = + channel->connection->localConf.maxMessageSize; + response->responseHeader.serviceResult |= + UA_ApplicationDescription_copy(&request->clientDescription, + &newSession->clientDescription); + + /* Prepare the response */ + response->sessionId = newSession->sessionId; + response->revisedSessionTimeout = (UA_Double)newSession->timeout; + response->authenticationToken = newSession->header.authenticationToken; + response->responseHeader.serviceResult |= + UA_String_copy(&request->sessionName, &newSession->sessionName); + + UA_ByteString_init(&response->serverCertificate); + + if(server->config.endpointsSize > 0) + for(size_t i = 0; i < response->serverEndpointsSize; ++i) { + if(response->serverEndpoints[i].securityMode==channel->securityMode && + UA_ByteString_equal(&response->serverEndpoints[i].securityPolicyUri, + &channel->securityPolicy->policyUri) && + UA_String_equal(&response->serverEndpoints[i].endpointUrl, + &request->endpointUrl)) + { + response->responseHeader.serviceResult |= + UA_ByteString_copy(&response->serverEndpoints[i].serverCertificate, + &response->serverCertificate); + } + } + + /* Create a session nonce */ + response->responseHeader.serviceResult |= UA_Session_generateNonce(newSession); + response->responseHeader.serviceResult |= + UA_ByteString_copy(&newSession->serverNonce, &response->serverNonce); + + /* Sign the signature */ + response->responseHeader.serviceResult |= + signCreateSessionResponse(server, channel, request, response); + + /* Failure -> remove the session */ + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_SessionManager_removeSession(&server->sessionManager, + &newSession->header.authenticationToken); + return; + } + + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, + "Session " UA_PRINTF_GUID_FORMAT " created", + UA_PRINTF_GUID_DATA(newSession->sessionId.identifier.guid)); +} + +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; + + if(!channel->securityPolicy) + return UA_STATUSCODE_BADINTERNALERROR; + const UA_SecurityPolicy *securityPolicy = channel->securityPolicy; + const UA_ByteString *localCertificate = &securityPolicy->localCertificate; + + size_t dataToVerifySize = localCertificate->length + session->serverNonce.length; + + UA_ByteString dataToVerify; + 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); + + retval = securityPolicy->certificateSigningAlgorithm.verify(securityPolicy, channel->channelContext, &dataToVerify, + &request->clientSignature.signature); + UA_ByteString_deleteMembers(&dataToVerify); + return retval; +} + +/* TODO: Check all of the following: + * + * Part 4, §5.6.3: When the ActivateSession Service is called for the first time + * then the Server shall reject the request if the SecureChannel is not same as + * the one associated with the CreateSession request. Subsequent calls to + * ActivateSession may be associated with different SecureChannels. If this is + * the case then 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 Server shall verify that the + * Client supplied a UserIdentityToken that is identical to the token currently + * associated with the Session. Once the Server accepts the new SecureChannel it + * shall reject requests sent via the old SecureChannel. */ + +void +Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel, + UA_Session *session, const UA_ActivateSessionRequest *request, + UA_ActivateSessionResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, "Execute ActivateSession"); + + if(session->validTill < UA_DateTime_nowMonotonic()) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "ActivateSession: SecureChannel %i wants " + "to activate, but the session has timed out", + channel->securityToken.channelId); + response->responseHeader.serviceResult = + UA_STATUSCODE_BADSESSIONIDINVALID; + return; + } + + /* 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_INFO_SESSION(server->config.logger, session, + "Signature check failed with status code %s", + UA_StatusCode_name(response->responseHeader.serviceResult)); + return; + } + + /* Callback into userland access control */ + response->responseHeader.serviceResult = + server->config.accessControl.activateSession(server, &server->config.accessControl, + &session->sessionId, &request->userIdentityToken, + &session->sessionHandle); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "ActivateSession: Could not generate a server nonce"); + return; + } + + if(session->header.channel && session->header.channel != channel) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "ActivateSession: Detach from old channel"); + /* Detach the old SecureChannel and attach the new */ + UA_Session_detachFromSecureChannel(session); + UA_Session_attachToSecureChannel(session, channel); + } + + /* Activate the session */ + session->activated = true; + UA_Session_updateLifetime(session); + + /* Generate a new session nonce for the next time ActivateSession is called */ + response->responseHeader.serviceResult = UA_Session_generateNonce(session); + response->responseHeader.serviceResult |= + UA_ByteString_copy(&session->serverNonce, &response->serverNonce); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_Session_detachFromSecureChannel(session); + session->activated = false; + UA_LOG_INFO_SESSION(server->config.logger, session, + "ActivateSession: Could not generate a server nonce"); + return; + } + + UA_LOG_INFO_SESSION(server->config.logger, session, + "ActivateSession: Session activated"); +} + +void +Service_CloseSession(UA_Server *server, UA_Session *session, + const UA_CloseSessionRequest *request, + UA_CloseSessionResponse *response) { + UA_LOG_INFO_SESSION(server->config.logger, session, "CloseSession"); + + /* Callback into userland access control */ + server->config.accessControl.closeSession(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle); + response->responseHeader.serviceResult = + UA_SessionManager_removeSession(&server->sessionManager, + &session->header.authenticationToken); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2015 (c) Christian Fimmers + * Copyright 2015-2016 (c) Chris Iatrou + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2015 (c) wuyangtang + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) Lorenz Haas + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Thomas Bender + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017 (c) Jonas Green + * Copyright 2017 (c) Henrik Norrman + */ + + +/******************/ +/* Access Control */ +/******************/ + +static UA_UInt32 +getUserWriteMask(UA_Server *server, const UA_Session *session, + const UA_Node *node) { + if(session == &server->adminSession) + return 0xFFFFFFFF; /* the local admin user has all rights */ + return node->writeMask & + server->config.accessControl.getUserRightsMask(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + &node->nodeId, node->context); +} + +static UA_Byte +getAccessLevel(UA_Server *server, const UA_Session *session, + const UA_VariableNode *node) { + if(session == &server->adminSession) + return 0xFF; /* the local admin user has all rights */ + return node->accessLevel; +} + +static UA_Byte +getUserAccessLevel(UA_Server *server, const UA_Session *session, + const UA_VariableNode *node) { + if(session == &server->adminSession) + return 0xFF; /* the local admin user has all rights */ + return node->accessLevel & + server->config.accessControl.getUserAccessLevel(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + &node->nodeId, node->context); +} + +static UA_Boolean +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 */ + return node->executable & + server->config.accessControl.getUserExecutable(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, + &node->nodeId, node->context); +} + +/****************/ +/* Read Service */ +/****************/ + +static UA_StatusCode +readArrayDimensionsAttribute(const UA_VariableNode *vn, UA_DataValue *v) { + UA_Variant_setArray(&v->value, vn->arrayDimensions, + vn->arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); + v->value.storageType = UA_VARIANT_DATA_NODELETE; + return UA_STATUSCODE_GOOD; +} + +static void +setScalarNoDelete(UA_Variant *v, const void * UA_RESTRICT p, + const UA_DataType *type) { + UA_Variant_setScalar(v, (void*)(uintptr_t)p, type); + v->storageType = UA_VARIANT_DATA_NODELETE; +} + +static UA_StatusCode +readIsAbstractAttribute(const UA_Node *node, UA_Variant *v) { + const UA_Boolean *isAbstract; + switch(node->nodeClass) { + case UA_NODECLASS_REFERENCETYPE: + isAbstract = &((const UA_ReferenceTypeNode*)node)->isAbstract; + break; + case UA_NODECLASS_OBJECTTYPE: + isAbstract = &((const UA_ObjectTypeNode*)node)->isAbstract; + break; + case UA_NODECLASS_VARIABLETYPE: + isAbstract = &((const UA_VariableTypeNode*)node)->isAbstract; + break; + case UA_NODECLASS_DATATYPE: + isAbstract = &((const UA_DataTypeNode*)node)->isAbstract; + break; + default: + return UA_STATUSCODE_BADATTRIBUTEIDINVALID; + } + + setScalarNoDelete(v, isAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]); + v->storageType = UA_VARIANT_DATA_NODELETE; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +readValueAttributeFromNode(UA_Server *server, UA_Session *session, + const UA_VariableNode *vn, UA_DataValue *v, + UA_NumericRange *rangeptr) { + if(vn->value.data.callback.onRead) { + vn->value.data.callback.onRead(server, &session->sessionId, + session->sessionHandle, &vn->nodeId, + vn->context, rangeptr, &vn->value.data.value); + const UA_Node *old = (const UA_Node *)vn; + /* Reopen the node to see the changes from onRead */ + vn = (const UA_VariableNode*)UA_Nodestore_get(server, &vn->nodeId); + UA_Nodestore_release(server, old); + } + if(rangeptr) + return UA_Variant_copyRange(&vn->value.data.value.value, &v->value, *rangeptr); + *v = vn->value.data.value; + v->value.storageType = UA_VARIANT_DATA_NODELETE; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +readValueAttributeFromDataSource(UA_Server *server, UA_Session *session, + const UA_VariableNode *vn, UA_DataValue *v, + UA_TimestampsToReturn timestamps, + UA_NumericRange *rangeptr) { + if(!vn->value.dataSource.read) + return UA_STATUSCODE_BADINTERNALERROR; + UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE || + timestamps == UA_TIMESTAMPSTORETURN_BOTH); + return vn->value.dataSource.read(server, &session->sessionId, session->sessionHandle, + &vn->nodeId, vn->context, sourceTimeStamp, rangeptr, v); +} + +static UA_StatusCode +readValueAttributeComplete(UA_Server *server, UA_Session *session, + const UA_VariableNode *vn, UA_TimestampsToReturn timestamps, + const UA_String *indexRange, UA_DataValue *v) { + /* Compute the index range */ + UA_NumericRange range; + UA_NumericRange *rangeptr = NULL; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(indexRange && indexRange->length > 0) { + retval = UA_NumericRange_parseFromString(&range, indexRange); + if(retval != UA_STATUSCODE_GOOD) + return retval; + 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); + + /* Clean up */ + if(rangeptr) + UA_free(range.dimensions); + return retval; +} + +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); +} + +static const UA_String binEncoding = {sizeof("Default Binary")-1, (UA_Byte*)"Default Binary"}; +static const UA_String xmlEncoding = {sizeof("Default XML")-1, (UA_Byte*)"Default XML"}; +static const UA_String jsonEncoding = {sizeof("Default JSON")-1, (UA_Byte*)"Default JSON"}; + +#define CHECK_NODECLASS(CLASS) \ + if(!(node->nodeClass & (CLASS))) { \ + retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; \ + break; \ + } + +/* Returns a datavalue that may point into the node via the + * UA_VARIANT_DATA_NODELETE tag. Don't access the returned DataValue once the + * node has been released! */ +static void +Read(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 %i", id->attributeId); + + /* Only Binary Encoding is supported */ + if(id->dataEncoding.name.length > 0 && + !UA_String_equal(&binEncoding, &id->dataEncoding.name)) { + if(UA_String_equal(&xmlEncoding, &id->dataEncoding.name) || + UA_String_equal(&jsonEncoding, &id->dataEncoding.name)) + v->status = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED; + else + v->status = UA_STATUSCODE_BADDATAENCODINGINVALID; + v->hasStatus = true; + return; + } + + /* Index range for an attribute other than value */ + if(id->indexRange.length > 0 && id->attributeId != UA_ATTRIBUTEID_VALUE) { + v->hasStatus = true; + v->status = UA_STATUSCODE_BADINDEXRANGENODATA; + return; + } + + /* Read the attribute */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + switch(id->attributeId) { + case UA_ATTRIBUTEID_NODEID: + setScalarNoDelete(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]); + break; + case UA_ATTRIBUTEID_NODECLASS: + setScalarNoDelete(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); + break; + case UA_ATTRIBUTEID_BROWSENAME: + setScalarNoDelete(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + break; + case UA_ATTRIBUTEID_DISPLAYNAME: + setScalarNoDelete(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + break; + case UA_ATTRIBUTEID_DESCRIPTION: + setScalarNoDelete(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + break; + case UA_ATTRIBUTEID_WRITEMASK: + setScalarNoDelete(&v->value, &node->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]); + break; } + case UA_ATTRIBUTEID_ISABSTRACT: + retval = readIsAbstractAttribute(node, &v->value); + break; + case UA_ATTRIBUTEID_SYMMETRIC: + CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE); + setScalarNoDelete(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric, + &UA_TYPES[UA_TYPES_BOOLEAN]); + break; + case UA_ATTRIBUTEID_INVERSENAME: + CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE); + setScalarNoDelete(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName, + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); + break; + case UA_ATTRIBUTEID_CONTAINSNOLOOPS: + CHECK_NODECLASS(UA_NODECLASS_VIEW); + setScalarNoDelete(&v->value, &((const UA_ViewNode*)node)->containsNoLoops, + &UA_TYPES[UA_TYPES_BOOLEAN]); + break; + case UA_ATTRIBUTEID_EVENTNOTIFIER: + CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); + setScalarNoDelete(&v->value, &((const UA_ViewNode*)node)->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) { + /* The access to a value variable is granted via the AccessLevel + * and UserAccessLevel attributes */ + UA_Byte accessLevel = getAccessLevel(server, session, (const UA_VariableNode*)node); + if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) { + retval = UA_STATUSCODE_BADNOTREADABLE; + break; + } + accessLevel = getUserAccessLevel(server, session, + (const UA_VariableNode*)node); + if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) { + retval = UA_STATUSCODE_BADUSERACCESSDENIED; + break; + } + } + retval = readValueAttributeComplete(server, session, (const UA_VariableNode*)node, + timestampsToReturn, &id->indexRange, v); + break; + } + case UA_ATTRIBUTEID_DATATYPE: + CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); + setScalarNoDelete(&v->value, &((const UA_VariableTypeNode*)node)->dataType, + &UA_TYPES[UA_TYPES_NODEID]); + break; + case UA_ATTRIBUTEID_VALUERANK: + CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); + setScalarNoDelete(&v->value, &((const UA_VariableTypeNode*)node)->valueRank, + &UA_TYPES[UA_TYPES_INT32]); + break; + case UA_ATTRIBUTEID_ARRAYDIMENSIONS: + CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); + retval = readArrayDimensionsAttribute((const UA_VariableNode*)node, v); + break; + case UA_ATTRIBUTEID_ACCESSLEVEL: + CHECK_NODECLASS(UA_NODECLASS_VARIABLE); + setScalarNoDelete(&v->value, &((const UA_VariableNode*)node)->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]); + break; } + case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL: + CHECK_NODECLASS(UA_NODECLASS_VARIABLE); + setScalarNoDelete(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval, + &UA_TYPES[UA_TYPES_DOUBLE]); + break; + case UA_ATTRIBUTEID_HISTORIZING: + CHECK_NODECLASS(UA_NODECLASS_VARIABLE); + setScalarNoDelete(&v->value, &((const UA_VariableNode*)node)->historizing, + &UA_TYPES[UA_TYPES_BOOLEAN]); + break; + case UA_ATTRIBUTEID_EXECUTABLE: + CHECK_NODECLASS(UA_NODECLASS_METHOD); + setScalarNoDelete(&v->value, &((const UA_MethodNode*)node)->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]); + break; } + default: + retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; + } + + /* Return error code when reading has failed */ + if(retval != UA_STATUSCODE_GOOD) { + v->hasStatus = true; + v->status = retval; + return; + } + + v->hasValue = true; + + /* Create server timestamp */ + if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER || + timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH) { + if (!v->hasServerTimestamp) { + v->serverTimestamp = UA_DateTime_now(); + v->hasServerTimestamp = true; + } + } + + /* Handle source time stamp */ + if(id->attributeId == UA_ATTRIBUTEID_VALUE) { + if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER || + timestampsToReturn == UA_TIMESTAMPSTORETURN_NEITHER) { + v->hasSourceTimestamp = false; + v->hasSourcePicoseconds = false; + } else if(!v->hasSourceTimestamp) { + v->sourceTimestamp = UA_DateTime_now(); + v->hasSourceTimestamp = true; + } + } +} + +static UA_StatusCode +Operation_Read(UA_Server *server, UA_Session *session, UA_MessageContext *mc, + UA_TimestampsToReturn timestampsToReturn, const UA_ReadValueId *id) { + UA_DataValue dv; + UA_DataValue_init(&dv); + + /* Get the node */ + const UA_Node *node = UA_Nodestore_get(server, &id->nodeId); + + /* Perform the read operation */ + if(node) { + Read(node, server, session, timestampsToReturn, id, &dv); + } else { + dv.hasStatus = true; + dv.status = UA_STATUSCODE_BADNODEIDUNKNOWN; + } + + /* Encode (and send) the results */ + UA_StatusCode retval = UA_MessageContext_encode(mc, &dv, &UA_TYPES[UA_TYPES_DATAVALUE]); + + /* Free copied data and release the node */ + UA_Variant_deleteMembers(&dv.value); + UA_Nodestore_release(server, node); + return retval; +} + +UA_StatusCode Service_Read(UA_Server *server, UA_Session *session, UA_MessageContext *mc, + const UA_ReadRequest *request, UA_ResponseHeader *responseHeader) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing ReadRequest"); + + /* Check if the timestampstoreturn is valid */ + if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) + responseHeader->serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID; + + if(request->nodesToReadSize == 0) + responseHeader->serviceResult = UA_STATUSCODE_BADNOTHINGTODO; + + /* Check if maxAge is valid */ + if(request->maxAge < 0) + responseHeader->serviceResult = UA_STATUSCODE_BADMAXAGEINVALID; + + /* Check if there are too many operations */ + if(server->config.maxNodesPerRead != 0 && + request->nodesToReadSize > server->config.maxNodesPerRead) + responseHeader->serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + + /* Encode the response header */ + UA_StatusCode retval = + UA_MessageContext_encode(mc, responseHeader, &UA_TYPES[UA_TYPES_RESPONSEHEADER]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Process nothing if we return an error code for the entire service */ + UA_Int32 arraySize = (UA_Int32)request->nodesToReadSize; + if(responseHeader->serviceResult != UA_STATUSCODE_GOOD) + arraySize = 0; + + /* Process all ReadValueIds */ + retval = UA_MessageContext_encode(mc, &arraySize, &UA_TYPES[UA_TYPES_INT32]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + for(UA_Int32 i = 0; i < arraySize; i++) { + retval = Operation_Read(server, session, mc, request->timestampsToReturn, + &request->nodesToRead[i]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Don't return any DiagnosticInfo */ + arraySize = -1; + return UA_MessageContext_encode(mc, &arraySize, &UA_TYPES[UA_TYPES_INT32]); +} + +UA_DataValue +UA_Server_readWithSession(UA_Server *server, UA_Session *session, + const UA_ReadValueId *item, + UA_TimestampsToReturn timestampsToReturn) { + UA_DataValue dv; + UA_DataValue_init(&dv); + + /* Get the node */ + const UA_Node *node = UA_Nodestore_get(server, &item->nodeId); + if(!node) { + dv.hasStatus = true; + dv.status = UA_STATUSCODE_BADNODEIDUNKNOWN; + return dv; + } + + /* Perform the read operation */ + Read(node, server, session, timestampsToReturn, item, &dv); + + /* Do we have to copy the result before releasing the node? */ + if(dv.hasValue && dv.value.storageType == UA_VARIANT_DATA_NODELETE) { + UA_DataValue dv2; + UA_StatusCode retval = UA_DataValue_copy(&dv, &dv2); + if(retval == UA_STATUSCODE_GOOD) { + dv = dv2; + } else { + UA_DataValue_init(&dv); + dv.hasStatus = true; + dv.status = retval; + } + } + + /* Release the node and return */ + UA_Nodestore_release(server, node); + return dv; +} + +/* Exposes the Read service to local users */ +UA_DataValue +UA_Server_read(UA_Server *server, const UA_ReadValueId *item, + UA_TimestampsToReturn timestamps) { + return UA_Server_readWithSession(server, &server->adminSession, item, timestamps); +} + +/* Used in inline functions exposing the Read service with more syntactic sugar + * for individual attributes */ +UA_StatusCode +__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, + const UA_AttributeId attributeId, void *v) { + /* Call the read service */ + UA_ReadValueId item; + UA_ReadValueId_init(&item); + item.nodeId = *nodeId; + item.attributeId = attributeId; + UA_DataValue dv = UA_Server_read(server, &item, UA_TIMESTAMPSTORETURN_NEITHER); + + /* Check the return value */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(dv.hasStatus) + retval = dv.status; + else if(!dv.hasValue) + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + if(retval != UA_STATUSCODE_GOOD) { + UA_DataValue_deleteMembers(&dv); + return retval; + } + + if(attributeId == UA_ATTRIBUTEID_VALUE || + attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS) { + /* Return the entire variant */ + memcpy(v, &dv.value, sizeof(UA_Variant)); + } else { + /* Return the variant content only */ + memcpy(v, dv.value.data, dv.value.type->memSize); + UA_free(dv.value.data); + } + return retval; +} + +/*****************/ +/* Type Checking */ +/*****************/ + +enum type_equivalence { + TYPE_EQUIVALENCE_NONE, + TYPE_EQUIVALENCE_ENUM, + TYPE_EQUIVALENCE_OPAQUE +}; + +static enum type_equivalence +typeEquivalence(const UA_DataType *t) { + if(t->membersSize != 1 || !t->members[0].namespaceZero) + return TYPE_EQUIVALENCE_NONE; + if(t->members[0].memberTypeIndex == UA_TYPES_INT32) + return TYPE_EQUIVALENCE_ENUM; + if(t->members[0].memberTypeIndex == UA_TYPES_BYTE && t->members[0].isArray) + return TYPE_EQUIVALENCE_OPAQUE; + return TYPE_EQUIVALENCE_NONE; +} + +const UA_NodeId subtypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}}; +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) { + /* Do not allow empty datatypes */ + if(UA_NodeId_isNull(dataType)) + return false; + + /* No constraint (TODO: use variant instead) */ + if(UA_NodeId_isNull(constraintDataType)) + 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)) + return true; + + /* Is the value-type a subtype of the required type? */ + if(isNodeInTree(&server->config.nodestore, dataType, constraintDataType, &subtypeId, 1)) + return true; + + /* Enum allows Int32 (only) */ + if(UA_NodeId_equal(dataType, &UA_TYPES[UA_TYPES_INT32].typeId) && + isNodeInTree(&server->config.nodestore, constraintDataType, &enumNodeId, &subtypeId, 1)) + 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->config.nodestore, constraintDataType, + dataType, &subtypeId, 1)) + return true; + } + + return false; +} + +/* Test whether a ValueRank and the given arraydimensions are compatible. + * + * 5.6.2 Variable NodeClass: If the maximum is unknown the value shall be 0. The + * number of elements shall be equal to the value of the ValueRank Attribute. + * This Attribute shall be null if ValueRank <= 0. */ +UA_Boolean +compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session, + UA_Int32 valueRank, size_t arrayDimensionsSize) { + /* ValueRank invalid */ + if(valueRank < UA_VALUERANK_SCALAR_OR_ONE_DIMENSION) { + UA_LOG_INFO_SESSION(server->config.logger, session, "The ValueRank is invalid (< -3)"); + 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 */ + if(valueRank <= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS) { + if(arrayDimensionsSize > 0) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "No ArrayDimensions can be defined for a ValueRank <= 0"); + return false; + } + return true; + } + + /* 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"); + return false; + } + return true; +} + +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 */ + 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 */ + 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 */ + 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 */ + if(valueRank != constraintValueRank) + return false; + break; + } + return true; +} + +/* Check if the ValueRank allows for the value dimension. This is more + * permissive than checking for the ArrayDimensions attribute. Because the value + * can have dimensions if the ValueRank < 0 */ +static UA_Boolean +compatibleValueRankValue(UA_Int32 valueRank, const UA_Variant *value) { + /* Invalid ValueRank */ + if(valueRank < UA_VALUERANK_SCALAR_OR_ONE_DIMENSION) + return false; + + /* Empty arrays (-1) always match */ + if(!value->data) + return true; + + size_t arrayDims = value->arrayDimensionsSize; + if(!arrayDims && !UA_Variant_isScalar(value)) + arrayDims = 1; /* array but no arraydimensions -> implicit array dimension 1 */ + + /* 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 */ + return (arrayDims <= 1); + 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); + default: + break; + } + + UA_assert(valueRank >= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS); + + /* case 0: the value is an array with one or more dimensions */ + return (arrayDims == (UA_UInt32)valueRank); +} + +UA_Boolean +compatibleArrayDimensions(size_t constraintArrayDimensionsSize, + const UA_UInt32 *constraintArrayDimensions, + size_t testArrayDimensionsSize, + const UA_UInt32 *testArrayDimensions) { + /* No array dimensions defined -> everything is permitted if the value rank fits */ + if(constraintArrayDimensionsSize == 0) + return true; + + /* Dimension count must match */ + if(testArrayDimensionsSize != constraintArrayDimensionsSize) + return false; + + /* Dimension lengths must match; zero in the constraint is a wildcard */ + for(size_t i = 0; i < constraintArrayDimensionsSize; ++i) { + if(constraintArrayDimensions[i] != testArrayDimensions[i] && + constraintArrayDimensions[i] != 0) + return false; + } + return true; +} + +UA_Boolean +compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimensionsSize, + const UA_UInt32 *targetArrayDimensions) { + size_t valueArrayDimensionsSize = value->arrayDimensionsSize; + UA_UInt32 *valueArrayDimensions = value->arrayDimensions; + UA_UInt32 tempArrayDimensions; + if(valueArrayDimensions == 0 && !UA_Variant_isScalar(value)) { + valueArrayDimensionsSize = 1; + tempArrayDimensions = (UA_UInt32)value->arrayLength; + valueArrayDimensions = &tempArrayDimensions; + } + return compatibleArrayDimensions(targetArrayDimensionsSize, targetArrayDimensions, + valueArrayDimensionsSize, valueArrayDimensions); +} + +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) { + /* Empty value */ + if(!value->type) { + /* Empty value is allowed for BaseDataType */ + if(UA_NodeId_equal(targetDataTypeId, &UA_TYPES[UA_TYPES_VARIANT].typeId) || + UA_NodeId_equal(targetDataTypeId, &UA_NODEID_NULL)) + return true; + + /* Workaround: Allow empty value if the target data type is abstract */ + const UA_Node *datatype = UA_Nodestore_get(server, targetDataTypeId); + if(datatype && datatype->nodeClass == UA_NODECLASS_DATATYPE) { + UA_Boolean isAbstract = ((const UA_DataTypeNode*)datatype)->isAbstract; + UA_Nodestore_release(server, datatype); + if(isAbstract) + return true; + } + + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Only Variables with data type BaseDataType may contain " + "a null (empty) value"); + return false; + } + + /* Has the value a subtype of the required type? BaseDataType (Variant) can + * be anything... */ + if(!compatibleDataType(server, &value->type->typeId, targetDataTypeId, true)) + 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)) + return false; + + /* Check if the valuerank allows for the value dimension */ + return compatibleValueRankValue(targetValueRank, value); +} + +/*****************/ +/* Write Service */ +/*****************/ + +static void +adjustValue(UA_Server *server, UA_Variant *value, + const UA_NodeId *targetDataTypeId) { + const UA_DataType *targetDataType = UA_findDataType(targetDataTypeId); + if(!targetDataType) + return; + + /* A string is written to a byte array. the valuerank and array dimensions + * are checked later */ + if(targetDataType == &UA_TYPES[UA_TYPES_BYTE] && + value->type == &UA_TYPES[UA_TYPES_BYTESTRING] && + UA_Variant_isScalar(value)) { + UA_ByteString *str = (UA_ByteString*)value->data; + value->type = &UA_TYPES[UA_TYPES_BYTE]; + value->arrayLength = str->length; + value->data = str->data; + return; + } + + /* An enum was sent as an int32, or an opaque type as a bytestring. This + * is detected with the typeIndex indicating the "true" datatype. */ + enum type_equivalence te1 = typeEquivalence(targetDataType); + enum type_equivalence te2 = typeEquivalence(value->type); + if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) { + value->type = targetDataType; + return; + } + + /* No more possible equivalencies */ +} + +static UA_StatusCode +writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_VariableTypeNode *type, + size_t arrayDimensionsSize, UA_UInt32 *arrayDimensions) { + UA_assert(node != NULL); + UA_assert(type != NULL); + + /* 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)) { + 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)) { + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "Cannot write the ArrayDimensions. The ValueRank does not match."); + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + /* Check if the array dimensions match with the wildcards in the + * variabletype (dimension length 0) */ + if(type->arrayDimensions && + !compatibleArrayDimensions(type->arrayDimensionsSize, type->arrayDimensions, + arrayDimensionsSize, arrayDimensions)) { + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "Array dimensions in the variable type do not match"); + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + /* Check if the current value is compatible with the array dimensions */ + UA_DataValue value; + UA_DataValue_init(&value); + UA_StatusCode retval = readValueAttribute(server, session, node, &value); + if(retval != UA_STATUSCODE_GOOD) + return retval; + if(value.hasValue) { + if(!compatibleValueArrayDimensions(&value.value, arrayDimensionsSize, arrayDimensions)) + retval = UA_STATUSCODE_BADTYPEMISMATCH; + UA_DataValue_deleteMembers(&value); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "Array dimensions in the current value do not match"); + return retval; + } + } + + /* Ok, apply */ + UA_UInt32 *oldArrayDimensions = node->arrayDimensions; + size_t oldArrayDimensionsSize = node->arrayDimensionsSize; + retval = UA_Array_copy(arrayDimensions, arrayDimensionsSize, + (void**)&node->arrayDimensions, + &UA_TYPES[UA_TYPES_UINT32]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + UA_Array_delete(oldArrayDimensions, oldArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); + node->arrayDimensionsSize = arrayDimensionsSize; + return UA_STATUSCODE_GOOD; +} + +/* Stack layout: ... | node | type */ +static UA_StatusCode +writeValueRankAttribute(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_VariableTypeNode *type, + UA_Int32 valueRank) { + UA_assert(node != NULL); + UA_assert(type != NULL); + + UA_Int32 constraintValueRank = type->valueRank; + + /* 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)) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Check if the valuerank of the variabletype allows the change. */ + if(!compatibleValueRanks(valueRank, constraintValueRank)) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* Check if the new valuerank is compatible with the array dimensions. Use + * the read service to handle data sources. */ + size_t arrayDims = node->arrayDimensionsSize; + if(arrayDims == 0) { + /* the value could be an array with no arrayDimensions defined. + dimensions zero indicate a scalar for compatibleValueRankArrayDimensions. */ + UA_DataValue value; + UA_DataValue_init(&value); + UA_StatusCode retval = readValueAttribute(server, session, node, &value); + if(retval != UA_STATUSCODE_GOOD) + return retval; + if(!value.hasValue || !value.value.type) { + /* no value -> apply */ + node->valueRank = valueRank; + return UA_STATUSCODE_GOOD; + } + if(!UA_Variant_isScalar(&value.value)) + arrayDims = 1; + UA_DataValue_deleteMembers(&value); + } + if(!compatibleValueRankArrayDimensions(server, session, valueRank, arrayDims)) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* All good, apply the change */ + node->valueRank = valueRank; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +writeDataTypeAttribute(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_VariableTypeNode *type, + const UA_NodeId *dataType) { + UA_assert(node != NULL); + UA_assert(type != NULL); + + /* 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)) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Does the new type match the constraints of the variabletype? */ + if(!compatibleDataType(server, dataType, &type->dataType, false)) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* Check if the current value would match the new type */ + UA_DataValue value; + UA_DataValue_init(&value); + UA_StatusCode retval = readValueAttribute(server, session, node, &value); + if(retval != UA_STATUSCODE_GOOD) + return retval; + if(value.hasValue) { + if(!compatibleValue(server, session, dataType, node->valueRank, + node->arrayDimensionsSize, node->arrayDimensions, + &value.value, NULL)) + retval = UA_STATUSCODE_BADTYPEMISMATCH; + UA_DataValue_deleteMembers(&value); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "The current value does not match the new data type"); + return retval; + } + } + + /* Replace the datatype nodeid */ + UA_NodeId dtCopy = node->dataType; + retval = UA_NodeId_copy(dataType, &node->dataType); + if(retval != UA_STATUSCODE_GOOD) { + node->dataType = dtCopy; + return retval; + } + UA_NodeId_deleteMembers(&dtCopy); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +writeValueAttributeWithoutRange(UA_VariableNode *node, const UA_DataValue *value) { + UA_DataValue new_value; + UA_StatusCode retval = UA_DataValue_copy(value, &new_value); + if(retval != UA_STATUSCODE_GOOD) + return retval; + UA_DataValue_deleteMembers(&node->value.data.value); + node->value.data.value = new_value; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +writeValueAttributeWithRange(UA_VariableNode *node, const UA_DataValue *value, + const UA_NumericRange *rangeptr) { + /* Value on both sides? */ + if(value->status != node->value.data.value.status || + !value->hasValue || !node->value.data.value.hasValue) + return UA_STATUSCODE_BADINDEXRANGEINVALID; + + /* Make scalar a one-entry array for range matching */ + UA_Variant editableValue; + const UA_Variant *v = &value->value; + if(UA_Variant_isScalar(&value->value)) { + editableValue = value->value; + editableValue.arrayLength = 1; + v = &editableValue; + } + + /* Check that the type is an exact match and not only "compatible" */ + if(!node->value.data.value.value.type || !v->type || + !UA_NodeId_equal(&node->value.data.value.value.type->typeId, + &v->type->typeId)) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* Write the value */ + UA_StatusCode retval = UA_Variant_setRangeCopy(&node->value.data.value.value, + v->data, v->arrayLength, *rangeptr); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Write the status and timestamps */ + node->value.data.value.hasStatus = value->hasStatus; + node->value.data.value.status = value->status; + node->value.data.value.hasSourceTimestamp = value->hasSourceTimestamp; + node->value.data.value.sourceTimestamp = value->sourceTimestamp; + node->value.data.value.hasSourcePicoseconds = value->hasSourcePicoseconds; + node->value.data.value.sourcePicoseconds = value->sourcePicoseconds; + return UA_STATUSCODE_GOOD; +} + +/* Stack layout: ... | node */ +static UA_StatusCode +writeValueAttribute(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_DataValue *value, + const UA_String *indexRange) { + UA_assert(node != NULL); + + /* Parse the range */ + UA_NumericRange range; + UA_NumericRange *rangeptr = NULL; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(indexRange && indexRange->length > 0) { + retval = UA_NumericRange_parseFromString(&range, indexRange); + if(retval != UA_STATUSCODE_GOOD) + return retval; + rangeptr = ⦥ + } + + /* Created an editable version. The data is not touched. Only the variant + * "container". */ + UA_DataValue adjustedValue = *value; + + /* Type checking. May change the type of editableValue */ + if(value->hasValue && value->value.type) { + adjustValue(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 + * extension object we check if the current node value is also an + * extension object. */ + UA_Boolean compatible; + if(value->value.type->typeId.identifierType == UA_NODEIDTYPE_NUMERIC && + value->value.type->typeId.identifier.numeric == UA_NS0ID_STRUCTURE) { + const UA_NodeId nodeDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE); + compatible = compatibleValue(server, session, &nodeDataType, node->valueRank, + node->arrayDimensionsSize, node->arrayDimensions, + &adjustedValue.value, rangeptr); + } else { + compatible = compatibleValue(server, session, &node->dataType, node->valueRank, + node->arrayDimensionsSize, node->arrayDimensions, + &adjustedValue.value, rangeptr); + } + + + if(!compatible) { + if(rangeptr) + UA_free(range.dimensions); + return UA_STATUSCODE_BADTYPEMISMATCH; + } + } + + /* 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; + } + + /* Ok, do it */ + if(node->valueSource == UA_VALUESOURCE_DATA) { + if(!rangeptr) + retval = writeValueAttributeWithoutRange(node, &adjustedValue); + else + retval = writeValueAttributeWithRange(node, &adjustedValue, rangeptr); + + /* Callback after writing */ + if(retval == UA_STATUSCODE_GOOD && node->value.data.callback.onWrite) + node->value.data.callback.onWrite(server, &session->sessionId, + session->sessionHandle, &node->nodeId, + node->context, rangeptr, + &adjustedValue); + } else { + if(node->value.dataSource.write) { + retval = node->value.dataSource.write(server, &session->sessionId, + session->sessionHandle, &node->nodeId, + node->context, rangeptr, &adjustedValue); + } else { + retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; + } + } + + /* Clean up */ + if(rangeptr) + UA_free(range.dimensions); + return retval; +} + +static UA_StatusCode +writeIsAbstractAttribute(UA_Node *node, UA_Boolean value) { + switch(node->nodeClass) { + case UA_NODECLASS_OBJECTTYPE: + ((UA_ObjectTypeNode*)node)->isAbstract = value; + break; + case UA_NODECLASS_REFERENCETYPE: + ((UA_ReferenceTypeNode*)node)->isAbstract = value; + break; + case UA_NODECLASS_VARIABLETYPE: + ((UA_VariableTypeNode*)node)->isAbstract = value; + break; + case UA_NODECLASS_DATATYPE: + ((UA_DataTypeNode*)node)->isAbstract = value; + break; + default: + return UA_STATUSCODE_BADNODECLASSINVALID; + } + return UA_STATUSCODE_GOOD; +} + +/*****************/ +/* Write Service */ +/*****************/ + +#define CHECK_DATATYPE_SCALAR(EXP_DT) \ + if(!wvalue->value.hasValue || \ + &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type || \ + !UA_Variant_isScalar(&wvalue->value.value)) { \ + retval = UA_STATUSCODE_BADTYPEMISMATCH; \ + break; \ + } + +#define CHECK_DATATYPE_ARRAY(EXP_DT) \ + if(!wvalue->value.hasValue || \ + &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type || \ + UA_Variant_isScalar(&wvalue->value.value)) { \ + retval = UA_STATUSCODE_BADTYPEMISMATCH; \ + break; \ + } + +#define CHECK_NODECLASS_WRITE(CLASS) \ + if((node->nodeClass & (CLASS)) == 0) { \ + retval = UA_STATUSCODE_BADNODECLASSINVALID; \ + break; \ + } + +#define CHECK_USERWRITEMASK(mask) \ + if(!(userWriteMask & (mask))) { \ + retval = UA_STATUSCODE_BADUSERACCESSDENIED; \ + break; \ + } + +#define GET_NODETYPE \ + type = (const UA_VariableTypeNode*) \ + getNodeType(server, node); \ + if(!type) { \ + retval = UA_STATUSCODE_BADTYPEMISMATCH; \ + break; \ + } + +/* 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) { + const void *value = wvalue->value.value.data; + UA_UInt32 userWriteMask = getUserWriteMask(server, session, node); + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + const UA_VariableTypeNode *type; + + switch(wvalue->attributeId) { + case UA_ATTRIBUTEID_NODEID: + case UA_ATTRIBUTEID_NODECLASS: + case UA_ATTRIBUTEID_USERWRITEMASK: + case UA_ATTRIBUTEID_USERACCESSLEVEL: + case UA_ATTRIBUTEID_USEREXECUTABLE: + retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; + break; + case UA_ATTRIBUTEID_BROWSENAME: + CHECK_USERWRITEMASK(UA_WRITEMASK_BROWSENAME); + CHECK_DATATYPE_SCALAR(QUALIFIEDNAME); + UA_QualifiedName_deleteMembers(&node->browseName); + UA_QualifiedName_copy((const UA_QualifiedName *)value, &node->browseName); + break; + case UA_ATTRIBUTEID_DISPLAYNAME: + CHECK_USERWRITEMASK(UA_WRITEMASK_DISPLAYNAME); + CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); + UA_LocalizedText_deleteMembers(&node->displayName); + UA_LocalizedText_copy((const UA_LocalizedText *)value, &node->displayName); + break; + case UA_ATTRIBUTEID_DESCRIPTION: + CHECK_USERWRITEMASK(UA_WRITEMASK_DESCRIPTION); + CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT); + UA_LocalizedText_deleteMembers(&node->description); + UA_LocalizedText_copy((const UA_LocalizedText *)value, &node->description); + break; + case UA_ATTRIBUTEID_WRITEMASK: + CHECK_USERWRITEMASK(UA_WRITEMASK_WRITEMASK); + CHECK_DATATYPE_SCALAR(UINT32); + node->writeMask = *(const UA_UInt32*)value; + break; + case UA_ATTRIBUTEID_ISABSTRACT: + CHECK_USERWRITEMASK(UA_WRITEMASK_ISABSTRACT); + CHECK_DATATYPE_SCALAR(BOOLEAN); + retval = writeIsAbstractAttribute(node, *(const UA_Boolean*)value); + break; + case UA_ATTRIBUTEID_SYMMETRIC: + CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); + CHECK_USERWRITEMASK(UA_WRITEMASK_SYMMETRIC); + CHECK_DATATYPE_SCALAR(BOOLEAN); + ((UA_ReferenceTypeNode*)node)->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); + UA_LocalizedText_deleteMembers(&((UA_ReferenceTypeNode*)node)->inverseName); + UA_LocalizedText_copy((const UA_LocalizedText *)value, + &((UA_ReferenceTypeNode*)node)->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; + break; + case UA_ATTRIBUTEID_EVENTNOTIFIER: + CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); + CHECK_USERWRITEMASK(UA_WRITEMASK_EVENTNOTIFIER); + CHECK_DATATYPE_SCALAR(BYTE); + ((UA_ViewNode*)node)->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) { + /* The access to a value variable is granted via the AccessLevel + * and UserAccessLevel attributes */ + UA_Byte accessLevel = getAccessLevel(server, session, (const UA_VariableNode*)node); + if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) { + retval = UA_STATUSCODE_BADNOTWRITABLE; + break; + } + accessLevel = getUserAccessLevel(server, session, + (const UA_VariableNode*)node); + if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) { + retval = UA_STATUSCODE_BADUSERACCESSDENIED; + break; + } + } else { /* UA_NODECLASS_VARIABLETYPE */ + CHECK_USERWRITEMASK(UA_WRITEMASK_VALUEFORVARIABLETYPE); + } + retval = writeValueAttribute(server, session, (UA_VariableNode*)node, + &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, + type, (const UA_NodeId*)value); + UA_Nodestore_release(server, (const UA_Node*)type); + break; + case UA_ATTRIBUTEID_VALUERANK: + 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, + type, *(const UA_Int32*)value); + UA_Nodestore_release(server, (const UA_Node*)type); + break; + case UA_ATTRIBUTEID_ARRAYDIMENSIONS: + 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, + type, wvalue->value.value.arrayLength, + (UA_UInt32 *)wvalue->value.value.data); + UA_Nodestore_release(server, (const UA_Node*)type); + break; + case UA_ATTRIBUTEID_ACCESSLEVEL: + CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); + CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVEL); + CHECK_DATATYPE_SCALAR(BYTE); + ((UA_VariableNode*)node)->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; + 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; + 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; + break; + default: + retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; + break; + } + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_INFO_SESSION(server->config.logger, session, + "WriteRequest returned status code %s", + UA_StatusCode_name(retval)); + return retval; +} + +static void +Operation_Write(UA_Server *server, UA_Session *session, void *context, + UA_WriteValue *wv, UA_StatusCode *result) { + *result = UA_Server_editNode(server, session, &wv->nodeId, + (UA_EditNodeCallback)copyAttributeIntoNode, wv); +} + +void +Service_Write(UA_Server *server, UA_Session *session, + const UA_WriteRequest *request, + UA_WriteResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing WriteRequest"); + + if(server->config.maxNodesPerWrite != 0 && + request->nodesToWriteSize > server->config.maxNodesPerWrite) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + 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_StatusCode +UA_Server_write(UA_Server *server, const UA_WriteValue *value) { + UA_StatusCode retval = + 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); + return retval; +} + +/* 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_WriteValue wvalue; + UA_WriteValue_init(&wvalue); + wvalue.nodeId = *nodeId; + wvalue.attributeId = attributeId; + wvalue.value.hasValue = true; + if(attr_type != &UA_TYPES[UA_TYPES_VARIANT]) { + /* hacked cast. the target WriteValue is used as const anyway */ + UA_Variant_setScalar(&wvalue.value.value, + (void*)(uintptr_t)attr, attr_type); + } else { + wvalue.value.value = *(const UA_Variant*)attr; + } + return UA_Server_write(server, &wvalue); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2016 (c) Sten Grüner + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2016 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#ifdef _WIN32 +# ifndef UNDER_CE +# include <io.h> //access +# define access _access +# endif +#else +# include <unistd.h> //access +#endif + +#ifdef UA_ENABLE_DISCOVERY + +static UA_StatusCode +setApplicationDescriptionFromRegisteredServer(const UA_FindServersRequest *request, + UA_ApplicationDescription *target, + const UA_RegisteredServer *registeredServer) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + UA_ApplicationDescription_init(target); + retval |= UA_String_copy(®isteredServer->serverUri, &target->applicationUri); + retval |= UA_String_copy(®isteredServer->productUri, &target->productUri); + + // if the client requests a specific locale, select the corresponding server name + if(request->localeIdsSize) { + UA_Boolean appNameFound = UA_FALSE; + for(size_t i =0; i<request->localeIdsSize && !appNameFound; i++) { + for(size_t j =0; j<registeredServer->serverNamesSize; j++) { + if(UA_String_equal(&request->localeIds[i], ®isteredServer->serverNames[j].locale)) { + retval |= UA_LocalizedText_copy(®isteredServer->serverNames[j], + &target->applicationName); + appNameFound = UA_TRUE; + break; + } + } + } + + // server does not have the requested local, therefore we can select the + // most suitable one + if(!appNameFound && registeredServer->serverNamesSize) + retval |= UA_LocalizedText_copy(®isteredServer->serverNames[0], + &target->applicationName); + } else if(registeredServer->serverNamesSize) { + // just take the first name + retval |= UA_LocalizedText_copy(®isteredServer->serverNames[0], &target->applicationName); + } + + target->applicationType = registeredServer->serverType; + retval |= UA_String_copy(®isteredServer->gatewayServerUri, &target->gatewayServerUri); + // TODO where do we get the discoveryProfileUri for application data? + + target->discoveryUrlsSize = registeredServer->discoveryUrlsSize; + if(registeredServer->discoveryUrlsSize) { + size_t duSize = sizeof(UA_String) * registeredServer->discoveryUrlsSize; + target->discoveryUrls = (UA_String *)UA_malloc(duSize); + if(!target->discoveryUrls) + return UA_STATUSCODE_BADOUTOFMEMORY; + for(size_t i = 0; i<registeredServer->discoveryUrlsSize; i++) + retval |= UA_String_copy(®isteredServer->discoveryUrls[i], &target->discoveryUrls[i]); + } + + return retval; +} +#endif + +static UA_StatusCode +setApplicationDescriptionFromServer(UA_ApplicationDescription *target, const UA_Server *server) { + /* Copy ApplicationDescription from the config */ + + UA_StatusCode result = UA_ApplicationDescription_copy(&server->config.applicationDescription, + target); + if(result != UA_STATUSCODE_GOOD) { + return result; + } + // UaExpert does not list DiscoveryServer, thus set it to Server + // See http://forum.unified-automation.com/topic1987.html + if(target->applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) + target->applicationType = UA_APPLICATIONTYPE_SERVER; + + /* add the discoveryUrls from the networklayers */ + size_t discSize = sizeof(UA_String) * (target->discoveryUrlsSize + server->config.networkLayersSize); + UA_String* disc = (UA_String *)UA_realloc(target->discoveryUrls, discSize); + if(!disc) { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + size_t existing = target->discoveryUrlsSize; + target->discoveryUrls = disc; + target->discoveryUrlsSize += server->config.networkLayersSize; + + // TODO: Add nl only if discoveryUrl not already present + for(size_t i = 0; i < server->config.networkLayersSize; i++) { + UA_ServerNetworkLayer* nl = &server->config.networkLayers[i]; + UA_String_copy(&nl->discoveryUrl, &target->discoveryUrls[existing + i]); + } + return UA_STATUSCODE_GOOD; +} + +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"); + + size_t foundServersSize = 0; + UA_ApplicationDescription *foundServers = NULL; + + UA_Boolean addSelf = UA_FALSE; + // temporarily store all the pointers which we found to avoid reiterating + // through the list + UA_RegisteredServer **foundServerFilteredPointer = NULL; + +#ifdef UA_ENABLE_DISCOVERY + // check if client only requested a specific set of servers + if(request->serverUrisSize) { + size_t fsfpSize = sizeof(UA_RegisteredServer*) * server->registeredServersSize; + foundServerFilteredPointer = (UA_RegisteredServer **)UA_malloc(fsfpSize); + if(!foundServerFilteredPointer) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + for(size_t i = 0; i < request->serverUrisSize; i++) { + if(!addSelf && UA_String_equal(&request->serverUris[i], + &server->config.applicationDescription.applicationUri)) { + addSelf = UA_TRUE; + } else { + registeredServer_list_entry* current; + LIST_FOREACH(current, &server->registeredServers, pointers) { + if(UA_String_equal(¤t->registeredServer.serverUri, &request->serverUris[i])) { + // check if entry already in list: + UA_Boolean existing = false; + for(size_t j=0; j<foundServersSize; j++) { + if(UA_String_equal(&foundServerFilteredPointer[j]->serverUri, &request->serverUris[i])) { + existing = true; + break; + } + } + if(!existing) + foundServerFilteredPointer[foundServersSize++] = ¤t->registeredServer; + break; + } + } + } + } + + if(addSelf) + foundServersSize++; + + } else { + addSelf = true; + // self + registered servers + foundServersSize = 1 + server->registeredServersSize; + } +#else + if(request->serverUrisSize) { + for(size_t i = 0; i < request->serverUrisSize; i++) { + if(UA_String_equal(&request->serverUris[i], + &server->config.applicationDescription.applicationUri)) { + addSelf = UA_TRUE; + foundServersSize = 1; + break; + } + } + } else { + addSelf = UA_TRUE; + foundServersSize = 1; + } +#endif + + if(foundServersSize) { + size_t fsSize = sizeof(UA_ApplicationDescription) * foundServersSize; + foundServers = (UA_ApplicationDescription *)UA_malloc(fsSize); + if(!foundServers) { + if(foundServerFilteredPointer) + UA_free(foundServerFilteredPointer); + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + if(addSelf) { + response->responseHeader.serviceResult = + setApplicationDescriptionFromServer(&foundServers[0], server); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_free(foundServers); + if(foundServerFilteredPointer) + UA_free(foundServerFilteredPointer); + return; + } + } + +#ifdef UA_ENABLE_DISCOVERY + size_t currentIndex = 0; + if(addSelf) + currentIndex++; + + // add all the registered servers to the list + + if(foundServerFilteredPointer) { + // use filtered list because client only requested specific uris + // -1 because foundServersSize also includes this self server + size_t iterCount = addSelf ? foundServersSize - 1 : foundServersSize; + for(size_t i = 0; i < iterCount; i++) { + response->responseHeader.serviceResult = + setApplicationDescriptionFromRegisteredServer(request, &foundServers[currentIndex++], + foundServerFilteredPointer[i]); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_free(foundServers); + UA_free(foundServerFilteredPointer); + return; + } + } + UA_free(foundServerFilteredPointer); + foundServerFilteredPointer = NULL; + } else { + registeredServer_list_entry* current; + LIST_FOREACH(current, &server->registeredServers, pointers) { + response->responseHeader.serviceResult = + setApplicationDescriptionFromRegisteredServer(request, &foundServers[currentIndex++], + ¤t->registeredServer); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_free(foundServers); + return; + } + } + } +#endif + } + + if(foundServerFilteredPointer) + UA_free(foundServerFilteredPointer); + + response->servers = foundServers; + response->serversSize = foundServersSize; +} + +void Service_GetEndpoints(UA_Server *server, UA_Session *session, + const UA_GetEndpointsRequest *request, + UA_GetEndpointsResponse *response) { + /* If the client expects to see a specific endpointurl, mirror it back. If + 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, + "Processing GetEndpointsRequest with endpointUrl " + UA_PRINTF_STRING_FORMAT, UA_PRINTF_STRING_DATA(*endpointUrl)); + } else { + UA_LOG_DEBUG_SESSION(server->config.logger, 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].endpointDescription.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; + if(endpointUrl->length == 0) { + clone_times = server->config.networkLayersSize; + nl_endpointurl = true; + } + + response->endpoints = + (UA_EndpointDescription*)UA_Array_new(relevant_count * 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 = UA_STATUSCODE_GOOD; + 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].endpointDescription, + &response->endpoints[k]); + retval |= UA_String_copy(endpointUrl, &response->endpoints[k].endpointUrl); + ++k; + } + } + + if(retval != UA_STATUSCODE_GOOD) { + response->responseHeader.serviceResult = retval; + UA_Array_delete(response->endpoints, response->endpointsSize, + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); + response->endpoints = NULL; + response->endpointsSize = 0; + return; + } +} + +#ifdef UA_ENABLE_DISCOVERY + +#ifdef UA_ENABLE_MULTITHREADING +static void +freeEntry(UA_Server *server, void *entry) { + UA_free(entry); +} +#endif + +static void +process_RegisterServer(UA_Server *server, UA_Session *session, + const UA_RequestHeader* requestHeader, + const UA_RegisteredServer *requestServer, + const size_t requestDiscoveryConfigurationSize, + const UA_ExtensionObject *requestDiscoveryConfiguration, + UA_ResponseHeader* responseHeader, + size_t *responseConfigurationResultsSize, + UA_StatusCode **responseConfigurationResults, + size_t *responseDiagnosticInfosSize, + UA_DiagnosticInfo *responseDiagnosticInfos) { + /* Find the server from the request in the registered list */ + registeredServer_list_entry* current; + registeredServer_list_entry *registeredServer_entry = NULL; + LIST_FOREACH(current, &server->registeredServers, pointers) { + if(UA_String_equal(¤t->registeredServer.serverUri, &requestServer->serverUri)) { + registeredServer_entry = current; + break; + } + } + + UA_MdnsDiscoveryConfiguration *mdnsConfig = NULL; + + const UA_String* mdnsServerName = NULL; + if(requestDiscoveryConfigurationSize) { + *responseConfigurationResults = + (UA_StatusCode *)UA_Array_new(requestDiscoveryConfigurationSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); + if(!(*responseConfigurationResults)) { + responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + *responseConfigurationResultsSize = requestDiscoveryConfigurationSize; + + for(size_t i = 0; i < requestDiscoveryConfigurationSize; i++) { + const UA_ExtensionObject *object = &requestDiscoveryConfiguration[i]; + if(!mdnsConfig && (object->encoding == UA_EXTENSIONOBJECT_DECODED || + object->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) && + (object->content.decoded.type == &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION])) { + mdnsConfig = (UA_MdnsDiscoveryConfiguration *)object->content.decoded.data; + mdnsServerName = &mdnsConfig->mdnsServerName; + (*responseConfigurationResults)[i] = UA_STATUSCODE_GOOD; + } else { + (*responseConfigurationResults)[i] = UA_STATUSCODE_BADNOTSUPPORTED; + } + } + } + + if(!mdnsServerName && requestServer->serverNamesSize) + mdnsServerName = &requestServer->serverNames[0].text; + + if(!mdnsServerName) { + responseHeader->serviceResult = UA_STATUSCODE_BADSERVERNAMEMISSING; + return; + } + + if(requestServer->discoveryUrlsSize == 0) { + responseHeader->serviceResult = UA_STATUSCODE_BADDISCOVERYURLMISSING; + return; + } + + if(requestServer->semaphoreFilePath.length) { +#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE + char* filePath = (char*) + UA_malloc(sizeof(char)*requestServer->semaphoreFilePath.length+1); + if(!filePath) { + UA_LOG_ERROR_SESSION(server->config.logger, session, + "Cannot allocate memory for semaphore path. Out of memory."); + responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + memcpy(filePath, requestServer->semaphoreFilePath.data, requestServer->semaphoreFilePath.length ); + filePath[requestServer->semaphoreFilePath.length] = '\0'; + if(access( filePath, 0 ) == -1) { + responseHeader->serviceResult = UA_STATUSCODE_BADSEMPAHOREFILEMISSING; + UA_free(filePath); + return; + } + UA_free(filePath); +#else + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_CLIENT, + "Ignoring semaphore file path. open62541 not compiled " + "with UA_ENABLE_DISCOVERY_SEMAPHORE=ON"); +#endif + } + +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) { + 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) || + (!requestServer->isOnline && i==requestServer->discoveryUrlsSize); + UA_Discovery_update_MdnsForDiscoveryUrl(server, mdnsServerName, mdnsConfig, + &requestServer->discoveryUrls[i], + requestServer->isOnline, updateTxt); + } + } +#endif + + if(!requestServer->isOnline) { + // server is shutting down. Remove it from the registered servers list + if(!registeredServer_entry) { + // server not found, show warning + UA_LOG_WARNING_SESSION(server->config.logger, session, + "Could not unregister server %.*s. Not registered.", + (int)requestServer->serverUri.length, requestServer->serverUri.data); + responseHeader->serviceResult = UA_STATUSCODE_BADNOTHINGTODO; + return; + } + + if(server->registerServerCallback) + server->registerServerCallback(requestServer, server->registerServerCallbackData); + + // server found, remove from list + LIST_REMOVE(registeredServer_entry, pointers); + UA_RegisteredServer_deleteMembers(®isteredServer_entry->registeredServer); +#ifndef UA_ENABLE_MULTITHREADING + UA_free(registeredServer_entry); + server->registeredServersSize--; +#else + UA_atomic_subSize(&server->registeredServersSize, 1); + UA_Server_delayedCallback(server, freeEntry, registeredServer_entry); +#endif + responseHeader->serviceResult = UA_STATUSCODE_GOOD; + return; + } + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(!registeredServer_entry) { + // server not yet registered, register it by adding it to the list + UA_LOG_DEBUG_SESSION(server->config.logger, session, "Registering new server: %.*s", + (int)requestServer->serverUri.length, requestServer->serverUri.data); + + registeredServer_entry = + (registeredServer_list_entry *)UA_malloc(sizeof(registeredServer_list_entry)); + if(!registeredServer_entry) { + responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + LIST_INSERT_HEAD(&server->registeredServers, registeredServer_entry, pointers); +#ifndef UA_ENABLE_MULTITHREADING + server->registeredServersSize++; +#else + UA_atomic_addSize(&server->registeredServersSize, 1); +#endif + + if(server->registerServerCallback) + server->registerServerCallback(requestServer, server->registerServerCallbackData); + } else { + UA_RegisteredServer_deleteMembers(®isteredServer_entry->registeredServer); + } + + // copy the data from the request into the list + UA_RegisteredServer_copy(requestServer, ®isteredServer_entry->registeredServer); + registeredServer_entry->lastSeen = UA_DateTime_nowMonotonic(); + responseHeader->serviceResult = retval; +} + +void Service_RegisterServer(UA_Server *server, UA_Session *session, + const UA_RegisterServerRequest *request, + UA_RegisterServerResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing RegisterServerRequest"); + process_RegisterServer(server, session, &request->requestHeader, &request->server, 0, + NULL, &response->responseHeader, 0, NULL, 0, NULL); +} + +void Service_RegisterServer2(UA_Server *server, UA_Session *session, + const UA_RegisterServer2Request *request, + UA_RegisterServer2Response *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing RegisterServer2Request"); + process_RegisterServer(server, session, &request->requestHeader, &request->server, + request->discoveryConfigurationSize, request->discoveryConfiguration, + &response->responseHeader, &response->configurationResultsSize, + &response->configurationResults, &response->diagnosticInfosSize, + response->diagnosticInfos); +} + +/* Cleanup server registration: If the semaphore file path is set, then it just + * checks the existence of the file. When it is deleted, the registration is + * removed. If there is no semaphore file, then the registration will be removed + * if it is older than 60 minutes. */ +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.discoveryCleanupTimeout) + timedOut -= server->config.discoveryCleanupTimeout*UA_DATETIME_SEC; + + registeredServer_list_entry* current, *temp; + LIST_FOREACH_SAFE(current, &server->registeredServers, pointers, temp) { + UA_Boolean semaphoreDeleted = UA_FALSE; + +#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE + if(current->registeredServer.semaphoreFilePath.length) { + size_t fpSize = sizeof(char)*current->registeredServer.semaphoreFilePath.length+1; + // todo: malloc may fail: return a statuscode + char* filePath = (char *)UA_malloc(fpSize); + if(filePath) { + memcpy(filePath, current->registeredServer.semaphoreFilePath.data, + current->registeredServer.semaphoreFilePath.length ); + filePath[current->registeredServer.semaphoreFilePath.length] = '\0'; +#ifdef UNDER_CE + FILE *fp = fopen(filePath,"rb"); + semaphoreDeleted = (fp==NULL); + if(fp) + fclose(fp); +#else + semaphoreDeleted = access( filePath, 0 ) == -1; +#endif + UA_free(filePath); + } else { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Cannot check registration semaphore. Out of memory"); + } + } +#endif + + if(semaphoreDeleted || (server->config.discoveryCleanupTimeout && + current->lastSeen < timedOut)) { + if(semaphoreDeleted) { + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Registration of server with URI %.*s is removed because " + "the semaphore file '%.*s' was deleted.", + (int)current->registeredServer.serverUri.length, + current->registeredServer.serverUri.data, + (int)current->registeredServer.semaphoreFilePath.length, + current->registeredServer.semaphoreFilePath.data); + } else { + // cppcheck-suppress unreadVariable + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Registration of server with URI %.*s has timed out and is removed.", + (int)current->registeredServer.serverUri.length, + current->registeredServer.serverUri.data); + } + LIST_REMOVE(current, pointers); + UA_RegisteredServer_deleteMembers(¤t->registeredServer); +#ifndef UA_ENABLE_MULTITHREADING + UA_free(current); + server->registeredServersSize--; +#else + UA_atomic_subSize(&server->registeredServersSize, 1); + UA_Server_delayedCallback(server, freeEntry, current); +#endif + } + } +} + +struct PeriodicServerRegisterCallback { + UA_UInt64 id; + UA_UInt32 this_interval; + UA_UInt32 default_interval; + UA_Boolean registered; + const char* discovery_server_url; +}; + +/* Called by the UA_Server callback. The OPC UA specification says: + * + * > If an error occurs during registration (e.g. the Discovery Server is not running) then the Server + * > must periodically re-attempt registration. The frequency of these attempts should start at 1 second + * > but gradually increase until the registration frequency is the same as what it would be if not + * > errors occurred. The recommended approach would double the period each attempt until reaching the maximum. + * + * We will do so by using the additional data parameter which holds information + * if the next interval is default or if it is a repeaded call. */ +static void +periodicServerRegister(UA_Server *server, void *data) { + UA_assert(data != NULL); + + struct PeriodicServerRegisterCallback *cb = (struct PeriodicServerRegisterCallback *)data; + + /* Which URL to register on */ + // fixme: remove magic url + const char * server_url; + if(cb->discovery_server_url != NULL) + server_url = cb->discovery_server_url; + else + server_url = "opc.tcp://localhost:4840"; + + /* Register + You can also use a semaphore file. That file must exist. When the file is + deleted, the server is automatically unregistered. The semaphore file has + to be accessible by the discovery server + + UA_StatusCode retval = UA_Server_register_discovery(server, + "opc.tcp://localhost:4840", "/path/to/some/file"); + */ + UA_StatusCode retval = UA_Server_register_discovery(server, server_url, NULL); + + /* Registering failed */ + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Could not register server with discovery server. " + "Is the discovery server started? StatusCode %s", + UA_StatusCode_name(retval)); + + /* If the server was previously registered, retry in one second, + * else, double the previous interval */ + UA_UInt32 nextInterval = 1000; + if(!cb->registered) + nextInterval = cb->this_interval * 2; + + /* The interval should be smaller than the default interval */ + if(nextInterval > cb->default_interval) + nextInterval = cb->default_interval; + + cb->this_interval = nextInterval; + UA_Server_changeRepeatedCallbackInterval(server, cb->id, nextInterval); + return; + } + + /* Registering succeeded */ + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "Server successfully registered. Next periodical register will be in %d seconds", + (int)(cb->default_interval/1000)); + + if(!cb->registered) { + retval = UA_Server_changeRepeatedCallbackInterval(server, cb->id, cb->default_interval); + /* If changing the interval fails, try again after the next registering */ + if(retval == UA_STATUSCODE_GOOD) + cb->registered = true; + } +} + +UA_StatusCode +UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, + const char* discoveryServerUrl, + UA_UInt32 intervalMs, + UA_UInt32 delayFirstRegisterMs, + UA_UInt64 *periodicCallbackId) { + + /* No valid server URL */ + if(!discoveryServerUrl) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "No discovery server URL provided"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + + /* check if we are already registering with the given discovery url and remove the old periodic call */ + { + periodicServerRegisterCallback_entry *rs, *rs_tmp; + LIST_FOREACH_SAFE(rs, &server->periodicServerRegisterCallbacks, pointers, rs_tmp) { + if(strcmp(rs->callback->discovery_server_url, discoveryServerUrl) == 0) { + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "There is already a register callback for '%s' in place. Removing the older one.", discoveryServerUrl); + UA_Server_removeRepeatedCallback(server, rs->callback->id); + LIST_REMOVE(rs, pointers); + UA_free(rs->callback); + UA_free(rs); + break; + } + } + } + + /* Allocate and initialize */ + struct PeriodicServerRegisterCallback* cb = + (struct PeriodicServerRegisterCallback*) + UA_malloc(sizeof(struct PeriodicServerRegisterCallback)); + if(!cb) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Start repeating a failed register after 1s, then increase the delay. Set + * to 500ms, as the delay is doubled before changing the callback + * interval.*/ + cb->this_interval = 500; + cb->default_interval = intervalMs; + cb->registered = false; + cb->discovery_server_url = discoveryServerUrl; + + + + /* Add the callback */ + UA_StatusCode retval = + UA_Server_addRepeatedCallback(server, periodicServerRegister, + cb, delayFirstRegisterMs, &cb->id); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Could not create periodic job for server register. " + "StatusCode %s", UA_StatusCode_name(retval)); + UA_free(cb); + return retval; + } + +#ifndef __clang_analyzer__ + // the analyzer reports on LIST_INSERT_HEAD a use after free false positive + periodicServerRegisterCallback_entry *newEntry = + (periodicServerRegisterCallback_entry *)UA_malloc(sizeof(periodicServerRegisterCallback_entry)); + if(!newEntry) { + UA_Server_removeRepeatedCallback(server, cb->id); + UA_free(cb); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + newEntry->callback = cb; + LIST_INSERT_HEAD(&server->periodicServerRegisterCallbacks, newEntry, pointers); +#endif + + if(periodicCallbackId) + *periodicCallbackId = cb->id; + return UA_STATUSCODE_GOOD; +} + +void +UA_Server_setRegisterServerCallback(UA_Server *server, + UA_Server_registerServerCallback cb, + void* data) { + server->registerServerCallback = cb; + server->registerServerCallbackData = data; +} + +#endif /* UA_ENABLE_DISCOVERY */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2016-2017 (c) Florian Palm + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mattias Bornhager + * Copyright 2017 (c) Henrik Norrman + * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA + */ + + +#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ + +#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; \ + } + +static UA_StatusCode +setSubscriptionSettings(UA_Server *server, UA_Subscription *subscription, + UA_Double requestedPublishingInterval, + UA_UInt32 requestedLifetimeCount, + UA_UInt32 requestedMaxKeepAliveCount, + UA_UInt32 maxNotificationsPerPublish, UA_Byte priority) { + /* deregister the callback if required */ + UA_StatusCode retval = Subscription_unregisterPublishCallback(server, subscription); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_SESSION(server->config.logger, subscription->session, + "Subscription %u | Could not unregister publish callback with error code %s", + subscription->subscriptionId, UA_StatusCode_name(retval)); + return retval; + } + + /* re-parameterize the subscription */ + subscription->publishingInterval = requestedPublishingInterval; + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.publishingIntervalLimits, + requestedPublishingInterval, subscription->publishingInterval); + /* check for nan*/ + if(requestedPublishingInterval != requestedPublishingInterval) + subscription->publishingInterval = server->config.publishingIntervalLimits.min; + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.keepAliveCountLimits, + requestedMaxKeepAliveCount, subscription->maxKeepAliveCount); + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.lifeTimeCountLimits, + requestedLifetimeCount, subscription->lifeTimeCount); + if(subscription->lifeTimeCount < 3 * subscription->maxKeepAliveCount) + subscription->lifeTimeCount = 3 * subscription->maxKeepAliveCount; + subscription->notificationsPerPublish = maxNotificationsPerPublish; + if(maxNotificationsPerPublish == 0 || + maxNotificationsPerPublish > server->config.maxNotificationsPerPublish) + subscription->notificationsPerPublish = server->config.maxNotificationsPerPublish; + subscription->priority = priority; + + retval = Subscription_registerPublishCallback(server, subscription); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_SESSION(server->config.logger, subscription->session, + "Subscription %u | Could not register publish callback with error code %s", + subscription->subscriptionId, UA_StatusCode_name(retval)); + return retval; + } + return UA_STATUSCODE_GOOD; +} + +void +Service_CreateSubscription(UA_Server *server, UA_Session *session, + const UA_CreateSubscriptionRequest *request, + UA_CreateSubscriptionResponse *response) { + /* Check limits for the number of subscriptions */ + if((server->config.maxSubscriptionsPerSession != 0) && + (session->numSubscriptions >= 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_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing CreateSubscriptionRequest failed"); + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + + UA_Session_addSubscription(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); + + if(retval != UA_STATUSCODE_GOOD) { + response->responseHeader.serviceResult = retval; + return; + } + + newSubscription->currentKeepAliveCount = newSubscription->maxKeepAliveCount; /* set settings first */ + + /* Prepare the response */ + response->subscriptionId = newSubscription->subscriptionId; + response->revisedPublishingInterval = newSubscription->publishingInterval; + response->revisedLifetimeCount = newSubscription->lifeTimeCount; + response->revisedMaxKeepAliveCount = newSubscription->maxKeepAliveCount; + + UA_LOG_INFO_SESSION(server->config.logger, session, "Subscription %u | " + "Created the Subscription with a publishing interval of %f ms", + response->subscriptionId, newSubscription->publishingInterval); +} + +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_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + UA_StatusCode retval = setSubscriptionSettings(server, sub, request->requestedPublishingInterval, + request->requestedLifetimeCount, request->requestedMaxKeepAliveCount, + request->maxNotificationsPerPublish, request->priority); + + if(retval != UA_STATUSCODE_GOOD) { + response->responseHeader.serviceResult = retval; + return; + } + + sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */ + response->revisedPublishingInterval = sub->publishingInterval; + response->revisedLifetimeCount = sub->lifeTimeCount; + response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount; +} + +static void +Operation_SetPublishingMode(UA_Server *Server, UA_Session *session, + UA_Boolean *publishingEnabled, UA_UInt32 *subscriptionId, + UA_StatusCode *result) { + UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId); + if(!sub) { + *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */ + sub->publishingEnabled = *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_Boolean publishingEnabled = request->publishingEnabled; /* request is const */ + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_SetPublishingMode, + &publishingEnabled, + &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32], + &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); +} + +static UA_StatusCode +setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon, + UA_MonitoringMode monitoringMode, + const UA_MonitoringParameters *params, + // This parameter is optional and used only if mon->lastValue is not set yet. + // Then numeric type will be detected from this value. Set null as defaut. + const UA_DataType* dataType) { + + /* Filter */ + if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED) { + UA_DataChangeFilter_init(&(mon->filter)); + mon->filter.trigger = UA_DATACHANGETRIGGER_STATUSVALUE; + } else if(params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) { + return UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID; + } else { + UA_DataChangeFilter *filter = (UA_DataChangeFilter *)params->filter.content.decoded.data; + // TODO implement EURange to support UA_DEADBANDTYPE_PERCENT + if (filter->deadbandType == UA_DEADBANDTYPE_PERCENT) { + return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED; + } + if (UA_Variant_isEmpty(&mon->lastValue)) { + if (!dataType || !isDataTypeNumeric(dataType)) + return UA_STATUSCODE_BADFILTERNOTALLOWED; + } else + if (!isDataTypeNumeric(mon->lastValue.type)) { + return UA_STATUSCODE_BADFILTERNOTALLOWED; + } + UA_DataChangeFilter_copy(filter, &(mon->filter)); + } + + MonitoredItem_unregisterSampleCallback(server, mon); + mon->monitoringMode = monitoringMode; + + /* ClientHandle */ + mon->clientHandle = params->clientHandle; + + /* SamplingInterval */ + UA_Double samplingInterval = params->samplingInterval; + 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); + } + } else if(mon->attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) { + /* TODO: events should not need a samplinginterval */ + samplingInterval = 10000.0f; // 10 seconds to reduce the load + } + mon->samplingInterval = samplingInterval; + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.samplingIntervalLimits, + samplingInterval, mon->samplingInterval); + if(samplingInterval != samplingInterval) /* Check for nan */ + mon->samplingInterval = server->config.samplingIntervalLimits.min; + + + /* QueueSize */ + UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits, + params->queueSize, mon->maxQueueSize); + + /* DiscardOldest */ + mon->discardOldest = params->discardOldest; + + /* Register sample callback if reporting is enabled */ + if(monitoringMode == UA_MONITORINGMODE_REPORTING) + return MonitoredItem_registerSampleCallback(server, mon); + + return UA_STATUSCODE_GOOD; +} + +static const UA_String binaryEncoding = {sizeof("Default Binary") - 1, (UA_Byte *)"Default Binary"}; + +/* Thread-local variables to pass additional arguments into the operation */ +struct createMonContext { + UA_Subscription *sub; + UA_TimestampsToReturn timestampsToReturn; +}; + +static void +Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct createMonContext *cmc, + const UA_MonitoredItemCreateRequest *request, + UA_MonitoredItemCreateResult *result) { + /* Check available capacity */ + if(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_deleteMembers(&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_deleteMembers(&v); + return; + } + + /* Check if the encoding is set for a value */ + if(request->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE && + request->itemToMonitor.dataEncoding.name.length > 0) { + result->statusCode = UA_STATUSCODE_BADDATAENCODINGINVALID; + UA_DataValue_deleteMembers(&v); + return; + } + + /* Create the monitoreditem */ + UA_MonitoredItem *newMon = UA_MonitoredItem_new(UA_MONITOREDITEMTYPE_CHANGENOTIFY); + if(!newMon) { + result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + UA_DataValue_deleteMembers(&v); + return; + } + UA_StatusCode retval = UA_NodeId_copy(&request->itemToMonitor.nodeId, + &newMon->monitoredNodeId); + if(retval != UA_STATUSCODE_GOOD) { + result->statusCode = retval; + MonitoredItem_delete(server, newMon); + UA_DataValue_deleteMembers(&v); + return; + } + newMon->subscription = cmc->sub; + newMon->attributeId = request->itemToMonitor.attributeId; + UA_String_copy(&request->itemToMonitor.indexRange, &newMon->indexRange); + newMon->monitoredItemId = ++cmc->sub->lastMonitoredItemId; + newMon->timestampsToReturn = cmc->timestampsToReturn; + retval = setMonitoredItemSettings(server, newMon, request->monitoringMode, + &request->requestedParameters, v.value.type); + UA_DataValue_deleteMembers(&v); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, cmc->sub->session, + "Subscription %u | Could not create a MonitoredItem " + "with StatusCode %s", cmc->sub->subscriptionId, + UA_StatusCode_name(retval)); + result->statusCode = retval; + MonitoredItem_delete(server, newMon); + --cmc->sub->lastMonitoredItemId; + return; + } + + UA_Subscription_addMonitoredItem(cmc->sub, newMon); + UA_LOG_INFO_SESSION(server->config.logger, cmc->sub->session, + "Subscription %u | MonitoredItem %i | " + "Created the MonitoredItem", cmc->sub->subscriptionId, + newMon->monitoredItemId); + + /* Create the first sample */ + if(request->monitoringMode == UA_MONITORINGMODE_REPORTING) + UA_MonitoredItem_SampleCallback(server, newMon); + + /* Prepare the response */ + result->revisedSamplingInterval = newMon->samplingInterval; + result->revisedQueueSize = newMon->maxQueueSize; + result->monitoredItemId = newMon->monitoredItemId; +} + +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"); + + if(server->config.maxMonitoredItemsPerCall != 0 && + request->itemsToCreateSize > server->config.maxMonitoredItemsPerCall) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + /* Check if the timestampstoreturn is valid */ + struct createMonContext cmc; + cmc.timestampsToReturn = request->timestampsToReturn; + if(cmc.timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID; + return; + } + + /* Find the subscription */ + cmc.sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!cmc.sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + /* Reset the subscription lifetime */ + 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]); +} + +static void +Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub, + const UA_MonitoredItemModifyRequest *request, + UA_MonitoredItemModifyResult *result) { + /* Get the MonitoredItem */ + UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, request->monitoredItemId); + if(!mon) { + result->statusCode = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + return; + } + UA_StatusCode retval; + retval = setMonitoredItemSettings(server, mon, mon->monitoringMode, &request->requestedParameters, NULL); + if(retval != UA_STATUSCODE_GOOD) { + result->statusCode = retval; + return; + } + + result->revisedSamplingInterval = mon->samplingInterval; + result->revisedQueueSize = mon->maxQueueSize; + + /* Remove some notifications if the queue is now too small */ + MonitoredItem_ensureQueueSpace(mon); +} + +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"); + + if(server->config.maxMonitoredItemsPerCall != 0 && + request->itemsToModifySize > server->config.maxMonitoredItemsPerCall) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + /* Check if the timestampstoreturn is valid */ + if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID; + return; + } + + /* Get the subscription */ + UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */ + + 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]); +} + +struct setMonitoringContext { + UA_Subscription *sub; + UA_MonitoringMode monitoringMode; +}; + +static void +Operation_SetMonitoringMode(UA_Server *server, UA_Session *session, + struct setMonitoringContext *smc, + UA_UInt32 *monitoredItemId, UA_StatusCode *result) { + UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(smc->sub, *monitoredItemId); + if(!mon) { + *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID; + return; + } + + if(mon->monitoredItemType != UA_MONITOREDITEMTYPE_CHANGENOTIFY) { + *result = UA_STATUSCODE_BADNOTIMPLEMENTED; + return; + } + + /* Check if the MonitoringMode is valid or not */ + if(smc->monitoringMode > UA_MONITORINGMODE_REPORTING) { + *result = UA_STATUSCODE_BADMONITORINGMODEINVALID; + return; + } + + if(mon->monitoringMode == smc->monitoringMode) + return; + + mon->monitoringMode = smc->monitoringMode; + if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) { + *result = MonitoredItem_registerSampleCallback(server, mon); + } else { + MonitoredItem_unregisterSampleCallback(server, mon); + + // TODO correctly implement SAMPLING + /* 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) { + TAILQ_REMOVE(&mon->queue, notification, listEntry); + TAILQ_REMOVE(&smc->sub->notificationQueue, notification, globalEntry); + --smc->sub->notificationQueueSize; + + UA_DataValue_deleteMembers(¬ification->data.value); + UA_free(notification); + } + mon->queueSize = 0; + + /* Initialize lastSampledValue */ + UA_ByteString_deleteMembers(&mon->lastSampledValue); + UA_Variant_deleteMembers(&mon->lastValue); + } +} + +void +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"); + + if(server->config.maxMonitoredItemsPerCall != 0 && + request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + /* Get the subscription */ + struct setMonitoringContext smc; + smc.sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!smc.sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + smc.sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */ + + 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]); +} + +/* TODO: Unify with senderror in ua_server_binary.c */ +static void +subscriptionSendError(UA_SecureChannel *channel, UA_UInt32 requestHandle, + UA_UInt32 requestId, UA_StatusCode error) { + UA_PublishResponse err_response; + UA_PublishResponse_init(&err_response); + err_response.responseHeader.requestHandle = requestHandle; + err_response.responseHeader.timestamp = UA_DateTime_now(); + err_response.responseHeader.serviceResult = error; + UA_SecureChannel_sendSymmetricMessage(channel, requestId, UA_MESSAGETYPE_MSG, + &err_response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); +} + +void +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"); + + /* Return an error if the session has no subscription */ + if(LIST_EMPTY(&session->serverSubscriptions)) { + subscriptionSendError(session->header.channel, request->requestHeader.requestHandle, + requestId, UA_STATUSCODE_BADNOSUBSCRIPTION); + return; + } + + /* 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)) { + subscriptionSendError(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADINTERNALERROR); + return; + } + } + + /* Allocate the response to store it in the retransmission queue */ + UA_PublishResponseEntry *entry = (UA_PublishResponseEntry *) + UA_malloc(sizeof(UA_PublishResponseEntry)); + if(!entry) { + subscriptionSendError(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADOUTOFMEMORY); + return; + } + + /* Prepare the response */ + entry->requestId = requestId; + UA_PublishResponse *response = &entry->response; + UA_PublishResponse_init(response); + response->responseHeader.requestHandle = request->requestHeader.requestHandle; + + /* Allocate the results array to acknowledge the acknowledge */ + if(request->subscriptionAcknowledgementsSize > 0) { + response->results = (UA_StatusCode *) + UA_Array_new(request->subscriptionAcknowledgementsSize, + &UA_TYPES[UA_TYPES_STATUSCODE]); + if(!response->results) { + UA_free(entry); + subscriptionSendError(session->header.channel, requestId, + request->requestHeader.requestHandle, + UA_STATUSCODE_BADOUTOFMEMORY); + return; + } + response->resultsSize = request->subscriptionAcknowledgementsSize; + } + + /* Delete Acknowledged Subscription Messages */ + for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; ++i) { + UA_SubscriptionAcknowledgement *ack = &request->subscriptionAcknowledgements[i]; + UA_Subscription *sub = UA_Session_getSubscriptionById(session, ack->subscriptionId); + if(!sub) { + response->results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Cannot process acknowledgements subscription %u", + ack->subscriptionId); + continue; + } + /* Remove the acked transmission from the retransmission queue */ + response->results[i] = UA_Subscription_removeRetransmissionMessage(sub, ack->sequenceNumber); + } + + /* Queue the publish response. It will be dequeued in a repeated publish + * callback. This can also be triggered right now for a late + * subscription. */ + UA_Session_queuePublishReq(session, entry, false); + 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; + } + } + } + + /* 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; + + repeat: + while(immediate) { + if(immediate->state == UA_SUBSCRIPTIONSTATE_LATE) { + session->lastSeenSubscriptionId = immediate->subscriptionId; + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Subscription %u | Response on a late subscription", + immediate->subscriptionId); + UA_Subscription_publish(server, immediate); + return; + } + immediate = LIST_NEXT(immediate, listEntry); + } + + /* Restart at the beginning of the list */ + if(found) { + immediate = LIST_FIRST(&session->serverSubscriptions); + found = false; + goto repeat; + } + + /* No late subscription this time */ + session->lastSeenSubscriptionId = 0; +} + +static void +Operation_DeleteSubscription(UA_Server *server, UA_Session *session, void *_, + 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 %u | Subscription deleted", + *subscriptionId); + } else { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Deleting Subscription with Id %u failed with error code %s", + *subscriptionId, UA_StatusCode_name(*result)); + } +} + +void +Service_DeleteSubscriptions(UA_Server *server, UA_Session *session, + const UA_DeleteSubscriptionsRequest *request, + UA_DeleteSubscriptionsResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing DeleteSubscriptionsRequest"); + + 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); +} + +static void +Operation_DeleteMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub, + UA_UInt32 *monitoredItemId, UA_StatusCode *result) { + *result = UA_Subscription_deleteMonitoredItem(server, sub, *monitoredItemId); +} + +void +Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session, + const UA_DeleteMonitoredItemsRequest *request, + UA_DeleteMonitoredItemsResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing DeleteMonitoredItemsRequest"); + + if(server->config.maxMonitoredItemsPerCall != 0 && + request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + /* Get the subscription */ + UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + /* Reset the subscription lifetime */ + sub->currentLifetimeCount = 0; + + 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]); +} + +void +Service_Republish(UA_Server *server, UA_Session *session, const UA_RepublishRequest *request, + UA_RepublishResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing RepublishRequest"); + + /* Get the subscription */ + UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return; + } + + /* Reset the subscription lifetime */ + sub->currentLifetimeCount = 0; + + /* Find the notification in the retransmission queue */ + UA_NotificationMessageEntry *entry; + TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) { + if(entry->message.sequenceNumber == request->retransmitSequenceNumber) + break; + } + if(!entry) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADMESSAGENOTAVAILABLE; + return; + } + + response->responseHeader.serviceResult = + UA_NotificationMessage_copy(&entry->message, &response->notificationMessage); +} + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +void +Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel *channel, + const UA_OpenSecureChannelRequest *request, + UA_OpenSecureChannelResponse *response) { + if(request->requestType == UA_SECURITYTOKENREQUESTTYPE_RENEW) { + /* Renew the channel */ + response->responseHeader.serviceResult = + UA_SecureChannelManager_renew(&server->secureChannelManager, + channel, request, response); + + /* Logging */ + if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, + "SecureChannel renewed"); + } else { + UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, + "Renewing SecureChannel failed"); + } + return; + } + + /* Must be ISSUE or RENEW */ + if(request->requestType != UA_SECURITYTOKENREQUESTTYPE_ISSUE) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + return; + } + + /* Open the channel */ + response->responseHeader.serviceResult = + UA_SecureChannelManager_open(&server->secureChannelManager, channel, + request, response); + + /* Logging */ + if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Opened SecureChannel"); + } else { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, + "Opening a SecureChannel failed"); + } +} + +/* The server does not send a CloseSecureChannel response */ +void +Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) { + UA_LOG_INFO_CHANNEL(server->config.logger, channel, "CloseSecureChannel"); + UA_SecureChannelManager_close(&server->secureChannelManager, + channel->securityToken.channelId); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015-2016 (c) Chris Iatrou + * Copyright 2015-2016 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Julian Grothoff + * Copyright 2016 (c) LEvertz + * Copyright 2016 (c) Lorenz Haas + * Copyright 2017 (c) frax2222 + * Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Christian von Arnim + * Copyright 2017 (c) Henrik Norrman + */ + + +/*********************/ +/* Edit Node Context */ +/*********************/ + +UA_StatusCode +UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId, + void **nodeContext) { + const UA_Node *node = UA_Nodestore_get(server, &nodeId); + if(!node) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + + *nodeContext = node->context; + UA_Nodestore_release(server, node); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +editNodeContext(UA_Server *server, UA_Session* session, + UA_Node* node, void *context) { + node->context = context; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId, + void *nodeContext) { + UA_StatusCode retval = + UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback)editNodeContext, nodeContext); + return retval; +} + +/**********************/ +/* Consistency Checks */ +/**********************/ + + +#define UA_PARENT_REFERENCES_COUNT 2 + +const UA_NodeId parentReferences[UA_PARENT_REFERENCES_COUNT] = { + { + 0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE} + }, + { + 0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT} + } +}; + + +/* 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, + const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) { + /* Objects do not need a parent (e.g. mandatory/optional modellingrules) */ + if(nodeClass == UA_NODECLASS_OBJECT && UA_NodeId_isNull(parentNodeId) && + UA_NodeId_isNull(referenceTypeId)) + return UA_STATUSCODE_GOOD; + + /* Omit checks during bootstrap */ + if(server->bootstrapNS0) + return UA_STATUSCODE_GOOD; + + /* See if the parent exists */ + const UA_Node *parent = UA_Nodestore_get(server, parentNodeId); + if(!parent) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Parent node not found"); + return UA_STATUSCODE_BADPARENTNODEIDINVALID; + } + + UA_NodeClass parentNodeClass = parent->nodeClass; + UA_Nodestore_release(server, parent); + + /* Check the referencetype exists */ + const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode*) + UA_Nodestore_get(server, referenceTypeId); + if(!referenceType) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: 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_INFO_SESSION(server->config.logger, session, + "AddNodes: Reference type to the parent invalid"); + UA_Nodestore_release(server, (const UA_Node*)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 */ + if(referenceTypeIsAbstract == true) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: 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: New type node need to have a " + "HasSubType reference"); + 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: New type node needs to be of the same " + "node type as the parent"); + return UA_STATUSCODE_BADPARENTNODEIDINVALID; + } + return UA_STATUSCODE_GOOD; + } + + /* Test if the referencetype is hierarchical */ + const UA_NodeId hierarchicalReference = + UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); + if(!isNodeInTree(&server->config.nodestore, referenceTypeId, + &hierarchicalReference, &subtypeId, 1)) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Reference type is not hierarchical"); + return UA_STATUSCODE_BADREFERENCETYPEIDINVALID; + } + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +typeCheckVariableNode(UA_Server *server, UA_Session *session, + const UA_VariableNode *node, + const UA_VariableTypeNode *vt, + const UA_NodeId *parentNodeId) { + /* 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; + + /* Check the datatype against the vt */ + if(!compatibleDataType(server, &node->dataType, &vt->dataType, false)) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* Check valueRank against array dimensions */ + if(!compatibleValueRankArrayDimensions(server, session, node->valueRank, node->arrayDimensionsSize)) + return UA_STATUSCODE_BADTYPEMISMATCH; + + /* If variable node is created below BaseObjectType and has its default valueRank of -2, + * skip the test */ + const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); + + // TODO handle subtypes of parent reference types + if(node->valueRank != vt->valueRank && + node->valueRank != UA_VariableAttributes_default.valueRank && + !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, + parentReferences, UA_PARENT_REFERENCES_COUNT)) { + /* Check valueRank against the vt */ + if(!compatibleValueRanks(node->valueRank, vt->valueRank)) + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + /* Check array dimensions against the vt */ + if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions, + node->arrayDimensionsSize, node->arrayDimensions)) + 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 = UA_Server_writeValue(server, node->nodeId, value.value); + UA_DataValue_deleteMembers(&value); + } + return retval; +} + +/********************/ +/* Instantiate Node */ +/********************/ + +static const UA_NodeId baseDataVariableType = + {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEDATAVARIABLETYPE}}; +static const UA_NodeId baseObjectType = + {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEOBJECTTYPE}}; + +/* Use attributes from the variable type wherever required */ +static UA_StatusCode +useVariableTypeAttributes(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_AddNodesItem *item) { + const UA_VariableAttributes *attributes = (const UA_VariableAttributes*) + item->nodeAttributes.content.decoded.data; + + /* Select the type definition */ + const UA_NodeId *typeDefinition; + if(node->nodeClass == UA_NODECLASS_VARIABLE) + typeDefinition = &item->typeDefinition.nodeId; + else /* UA_NODECLASS_VARIABLETYPE */ + typeDefinition = &item->parentNodeId.nodeId; + + /* Replace an empty typeDefinition with the most permissive default */ + if(UA_NodeId_isNull(typeDefinition)) + typeDefinition = &baseDataVariableType; + + const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*) + UA_Nodestore_get(server, typeDefinition); + if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE) { + UA_Nodestore_release(server, (const UA_Node*)vt); + return UA_STATUSCODE_BADTYPEMISMATCH; + } + + /* 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_StatusCode retval = UA_STATUSCODE_GOOD; + if(!attributes->value.type) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "AddNodes: No value given; Copy the value" + "from the TypeDefinition"); + UA_DataValue vt_value; + UA_DataValue_init(&vt_value); + retval = readValueAttribute(server, session, + (const UA_VariableNode*)vt, &vt_value); + if(retval == UA_STATUSCODE_GOOD && vt_value.hasValue) { + retval = UA_Variant_copy(&vt_value.value, &node->value.data.value.value); + node->value.data.value.hasValue = true; + } + UA_DataValue_deleteMembers(&vt_value); + } + + /* If no datatype is given, use the datatype of the vt */ + if(retval == UA_STATUSCODE_GOOD && UA_NodeId_isNull(&node->dataType)) { + UA_LOG_INFO_SESSION(server->config.logger, session, "AddNodes: " + "No datatype given; Copy the datatype attribute " + "from the TypeDefinition"); + retval = UA_NodeId_copy(&vt->dataType, &node->dataType); + } + + /* TODO: If the vt has arraydimensions but this variable does not, copy */ + + UA_Nodestore_release(server, (const UA_Node*)vt); + return retval; +} + +/* Search for an instance of "browseName" in node searchInstance. Used during + * copyChildNodes to find overwritable/mergable nodes. Does not touch + * outInstanceNodeId if no child is found. */ +static UA_StatusCode +findChildByBrowsename(UA_Server *server, UA_Session *session, + const UA_NodeId *searchInstance, + const UA_QualifiedName *browseName, + UA_NodeId *outInstanceNodeId) { + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = *searchInstance; + bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); + bd.includeSubtypes = true; + bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; + bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD; + bd.resultMask = UA_BROWSERESULTMASK_NODECLASS | UA_BROWSERESULTMASK_BROWSENAME; + + 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 br.statusCode; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < br.referencesSize; ++i) { + UA_ReferenceDescription *rd = &br.references[i]; + if(rd->browseName.namespaceIndex == browseName->namespaceIndex && + UA_String_equal(&rd->browseName.name, &browseName->name)) { + retval = UA_NodeId_copy(&rd->nodeId.nodeId, outInstanceNodeId); + break; + } + } + + UA_BrowseResult_deleteMembers(&br); + return retval; +} + +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, + const UA_NodeId *childNodeId) { + /* Get the child */ + const UA_Node *child = UA_Nodestore_get(server, childNodeId); + if(!child) + 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)) + continue; + if(refs->isInverse) + continue; + for(size_t j = 0; j < refs->targetIdsSize; ++j) { + if(UA_NodeId_equal(&mandatoryId, &refs->targetIds[j].nodeId)) { + UA_Nodestore_release(server, child); + return true; + } + } + } + + UA_Nodestore_release(server, child); + return false; +} + +static UA_StatusCode +copyChildNodes(UA_Server *server, UA_Session *session, + const UA_NodeId *sourceNodeId, + const UA_NodeId *destinationNodeId); + +static void +Operation_addReference(UA_Server *server, UA_Session *session, void *context, + const UA_AddReferencesItem *item, UA_StatusCode *retval); + + +/* + * This method only 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' + */ +static void deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, UA_NodeId* referencesSkip) { + if(referencesSkipSize == 0) { + UA_Node_deleteReferences(node); + return; + } + + /* Let's count if there are references left. If not just delete all the references. + * It's faster */ + size_t newSize = 0; + for(size_t i = 0; i < node->referencesSize; ++i) { + for(size_t j = 0; j < referencesSkipSize; j++) { + if(UA_NodeId_equal(&node->references[i].referenceTypeId, &referencesSkip[j])) { + newSize++; + } + } + } + if(newSize == 0) { + UA_Node_deleteReferences(node); + return; + } + + /* Now copy the remaining references to a new array */ + UA_NodeReferenceKind *newReferences = (UA_NodeReferenceKind *)UA_malloc(sizeof(UA_NodeReferenceKind) * (newSize)); + size_t curr = 0; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; ++i) { + for(size_t j = 0; j < referencesSkipSize; j++) { + if(!UA_NodeId_equal(&node->references[i].referenceTypeId, &referencesSkip[j])) + continue; + + // copy the reference + UA_NodeReferenceKind *srefs = &node->references[i]; + UA_NodeReferenceKind *drefs = &newReferences[curr++]; + drefs->isInverse = srefs->isInverse; + retval = UA_NodeId_copy(&srefs->referenceTypeId, &drefs->referenceTypeId); + if(retval != UA_STATUSCODE_GOOD) + break; + retval = UA_Array_copy(srefs->targetIds, srefs->targetIdsSize, + (void**)&drefs->targetIds, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + if(retval != UA_STATUSCODE_GOOD) + break; + drefs->targetIdsSize = srefs->targetIdsSize; + break; + } + if(retval != UA_STATUSCODE_GOOD) { + for(size_t k=0; k<i; k++) { + UA_NodeReferenceKind *refs = &newReferences[i]; + for(size_t j = 0; j < refs->targetIdsSize; ++j) + UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]); + UA_Array_delete(refs->targetIds, refs->targetIdsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_NodeId_deleteMembers(&refs->referenceTypeId); + } + } + } + + UA_Node_deleteReferences(node); + if(retval == UA_STATUSCODE_GOOD) { + node->references = newReferences; + node->referencesSize = newSize; + } else { + UA_free(newReferences); + } +} + +static UA_StatusCode +AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, + const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, + const UA_NodeId *typeDefinitionId); + +static UA_StatusCode +copyChildNode(UA_Server *server, UA_Session *session, + const UA_NodeId *destinationNodeId, + const UA_ReferenceDescription *rd) { + UA_NodeId existingChild = UA_NODEID_NULL; + UA_StatusCode retval = + findChildByBrowsename(server, session, destinationNodeId, + &rd->browseName, &existingChild); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Have a child with that browseName. Try to deep-copy missing members. */ + if(!UA_NodeId_isNull(&existingChild)) { + if(rd->nodeClass == UA_NODECLASS_VARIABLE || + rd->nodeClass == UA_NODECLASS_OBJECT) + retval = copyChildNodes(server, session, &rd->nodeId.nodeId, &existingChild); + UA_NodeId_deleteMembers(&existingChild); + return retval; + } + + /* Is the child mandatory? If not, skip */ + if(!isMandatoryChild(server, session, &rd->nodeId.nodeId)) + return UA_STATUSCODE_GOOD; + + /* No existing child with that browsename. Create it. */ + if(rd->nodeClass == UA_NODECLASS_METHOD) { + /* Add a reference to the method in the objecttype */ + UA_AddReferencesItem newItem; + UA_AddReferencesItem_init(&newItem); + newItem.sourceNodeId = *destinationNodeId; + newItem.referenceTypeId = rd->referenceTypeId; + newItem.isForward = true; + newItem.targetNodeId = rd->nodeId; + newItem.targetNodeClass = UA_NODECLASS_METHOD; + Operation_addReference(server, session, NULL, &newItem, &retval); + return retval; + } + + /* Node exists and is a variable or object. Instantiate missing mandatory + * children */ + if(rd->nodeClass == UA_NODECLASS_VARIABLE || + rd->nodeClass == UA_NODECLASS_OBJECT) { + /* Get the node */ + UA_Node *node; + retval = UA_Nodestore_getCopy(server, &rd->nodeId.nodeId, &node); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Get the type */ + const UA_Node *type = getNodeType(server, node); + const UA_NodeId *typeId; + if(type) + typeId = &type->nodeId; + else + typeId = &UA_NODEID_NULL; + + /* Reset the NodeId (random numeric id will be assigned in the nodestore) */ + UA_NodeId_deleteMembers(&node->nodeId); + node->nodeId.namespaceIndex = destinationNodeId->namespaceIndex; + + /* 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); + deleteReferencesSubset(node, 1, &modellingRuleReferenceId); + + /* Add the node to the nodestore */ + UA_NodeId newNodeId; + retval = UA_Nodestore_insert(server, node, &newNodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_Nodestore_release(server, type); + return retval; + } + + /* Add all the children of this child to the new child node to make sure we take + * the values from the nearest inherited object first. + * The call to addNode_finish will then only add the children from the type and + * thus skip the direct children of rd->nodeId.nodeId */ + copyChildNodes(server, session, &rd->nodeId.nodeId, &newNodeId); + + /* Add the parent reference */ + retval = AddNode_typeCheckAddRefs(server, session, &newNodeId, destinationNodeId, + &rd->referenceTypeId, typeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_Nodestore_delete(server, node); + UA_Nodestore_release(server, type); + return retval; + } + + /* Call addnode_finish, this recursively adds additional members, the type + * definition and so on of the base type of this child, if they are not yet + * in the destination */ + retval |= Operation_addNode_finish(server, session, &newNodeId); + UA_NodeId_deleteMembers(&newNodeId); + UA_Nodestore_release(server, type); + } + return retval; +} + +/* Copy any children of Node sourceNodeId to another node destinationNodeId. */ +static UA_StatusCode +copyChildNodes(UA_Server *server, UA_Session *session, + const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId) { + /* Browse to get all children of the source */ + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = *sourceNodeId; + bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); + bd.includeSubtypes = true; + bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; + bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD; + bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS | + UA_BROWSERESULTMASK_BROWSENAME; + + 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 br.statusCode; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < br.referencesSize; ++i) { + UA_ReferenceDescription *rd = &br.references[i]; + retval |= copyChildNode(server, session, destinationNodeId, rd); + } + + UA_BrowseResult_deleteMembers(&br); + return retval; +} + +static UA_StatusCode +addChildren(UA_Server *server, UA_Session *session, + const UA_Node *node, const UA_Node *type) { + /* Get the hierarchy of the type and all its supertypes */ + UA_NodeId *hierarchy = NULL; + size_t hierarchySize = 0; + UA_StatusCode retval = getTypeHierarchy(&server->config.nodestore, &type->nodeId, + &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 |= copyChildNodes(server, session, &hierarchy[i], &node->nodeId); + UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]); + return retval; +} + +/* Calls the global destructor internally of the global constructor succeeds and + * the type-level constructor fails. */ +static UA_StatusCode callConstructors(UA_Server *server, UA_Session *session, + const UA_Node *node, const UA_Node *type) { + /* Get the node type constructor */ + const UA_NodeTypeLifecycle *lifecycle = NULL; + if(node->nodeClass == UA_NODECLASS_OBJECT) { + const UA_ObjectTypeNode *ot = (const UA_ObjectTypeNode*)type; + lifecycle = &ot->lifecycle; + } else if(node->nodeClass == UA_NODECLASS_VARIABLE) { + const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)type; + lifecycle = &vt->lifecycle; + } + + /* Call the global constructor */ + void *context = node->context; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(server->config.nodeLifecycle.constructor) + retval = server->config.nodeLifecycle.constructor(server, &session->sessionId, + session->sessionHandle, + &node->nodeId, &context); + + /* Call the type constructor */ + if(retval == UA_STATUSCODE_GOOD && lifecycle && lifecycle->constructor) + retval = lifecycle->constructor(server, &session->sessionId, + session->sessionHandle, &type->nodeId, + type->context, &node->nodeId, &context); + + /* 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)editNodeContext, + context); + + /* Fail. Call the global destructor. */ + if(retval != UA_STATUSCODE_GOOD && server->config.nodeLifecycle.destructor) + server->config.nodeLifecycle.destructor(server, &session->sessionId, + session->sessionHandle, + &node->nodeId, context); + + return retval; +} + +static UA_StatusCode +addTypeDefRef(UA_Server *server, UA_Session *session, + const UA_Node *node, const UA_Node *type) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_AddReferencesItem addref; + UA_AddReferencesItem_init(&addref); + addref.sourceNodeId = node->nodeId; + addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); + addref.isForward = true; + addref.targetNodeId.nodeId = type->nodeId; + Operation_addReference(server, session, NULL, &addref, &retval); + return retval; +} + +static UA_StatusCode +getTypeDef(UA_Server *server, const UA_Node *node, UA_NodeId **typeDefinitionId) { + UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); + for (size_t i=0; i< node->referencesSize; i++) { + if (node->references[i].isInverse == UA_FALSE && UA_NodeId_equal(&node->references[i].referenceTypeId, &hasTypeDef) && + node->references[i].targetIdsSize > 0) { + *typeDefinitionId = &node->references[i].targetIds[0].nodeId; + return UA_STATUSCODE_GOOD; + } + } + + return UA_STATUSCODE_BADNOTFOUND; +} + +static UA_StatusCode +addParentRef(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, + const UA_NodeId *referenceTypeId, + const UA_NodeId *parentNodeId) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_AddReferencesItem ref_item; + UA_AddReferencesItem_init(&ref_item); + ref_item.sourceNodeId = *nodeId; + ref_item.referenceTypeId = *referenceTypeId; + ref_item.isForward = false; + ref_item.targetNodeId.nodeId = *parentNodeId; + Operation_addReference(server, session, NULL, &ref_item, &retval); + return retval; +} + +/************/ +/* Add Node */ +/************/ + +static void +removeDeconstructedNode(UA_Server *server, UA_Session *session, + const UA_Node *node, UA_Boolean removeTargetRefs); + +static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}}; + +static UA_StatusCode +AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, + const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, + const UA_NodeId *typeDefinitionId) { + /* Get the node */ + const UA_Node *node = UA_Nodestore_get(server, nodeId); + if(!node) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + const UA_Node *type = NULL; + + /* 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) { + 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) + typeDefinitionId = parentNodeId; + UA_Nodestore_release(server, parentNode); + } + } + + if(server->bootstrapNS0) + goto get_type; + + /* Check parent reference. Objects may have no parent. */ + retval = checkParentReference(server, session, node->nodeClass, + parentNodeId, referenceTypeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: The parent reference is invalid"); + goto cleanup; + } + + /* Replace empty typeDefinition with the most permissive default */ + if((node->nodeClass == UA_NODECLASS_VARIABLE || + node->nodeClass == UA_NODECLASS_OBJECT) && + UA_NodeId_isNull(typeDefinitionId)) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: No TypeDefinition; Use the default " + "TypeDefinition for the Variable/Object"); + if(node->nodeClass == UA_NODECLASS_VARIABLE) + typeDefinitionId = &baseDataVariableType; + else + typeDefinitionId = &baseObjectType; + } + + get_type: + /* Get the node type. There must be a typedefinition for variables, objects + * and type-nodes. See the above checks. */ + if(!UA_NodeId_isNull(typeDefinitionId)) { + /* Get the type node */ + type = UA_Nodestore_get(server, typeDefinitionId); + if(!type) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Node type not found in nodestore"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; + } + + UA_Boolean typeOk = UA_FALSE; + switch(node->nodeClass) { + case UA_NODECLASS_DATATYPE: + typeOk = type->nodeClass == UA_NODECLASS_DATATYPE; + break; + case UA_NODECLASS_METHOD: + typeOk = type->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; + break; + case UA_NODECLASS_REFERENCETYPE: + typeOk = type->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; + break; + case UA_NODECLASS_VIEW: + typeOk = type->nodeClass == UA_NODECLASS_VIEW; + break; + default: + typeOk = UA_FALSE; + } + if(!typeOk) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Type does not match node class"); + 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(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_VARIABLE) { + if(((const UA_VariableTypeNode*)type)->isAbstract) { + /* Abstract variable is allowed if parent is a children of a base data variable */ + const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE); + /* A variable may be of an object type which again is below BaseObjectType */ + const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); + // TODO handle subtypes of parent reference types + if(!isNodeInTree(&server->config.nodestore, parentNodeId, &variableTypes, + parentReferences, UA_PARENT_REFERENCES_COUNT) && + !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, + parentReferences, UA_PARENT_REFERENCES_COUNT)) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Type of variable node must " + "be VariableType and not cannot be abstract"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; + } + } + } + + if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_OBJECT) { + if(((const UA_ObjectTypeNode*)type)->isAbstract) { + /* Object node created of an abstract ObjectType. Only allowed + * if within BaseObjectType folder */ + const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE); + // TODO handle subtypes of parent reference types + if(!isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, + parentReferences, UA_PARENT_REFERENCES_COUNT)) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Type of object node must " + "be ObjectType and not be abstract"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; + } + } + } + } + + /* 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. */ + if(type && (node->nodeClass == UA_NODECLASS_VARIABLE || + node->nodeClass == UA_NODECLASS_VARIABLETYPE)) { + retval = typeCheckVariableNode(server, session, (const UA_VariableNode*)node, + (const UA_VariableTypeNode*)type, parentNodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Type-checking the variable node " + "failed with error code %s", UA_StatusCode_name(retval)); + goto cleanup; + } + } + + /* Add reference to the parent */ + if(!UA_NodeId_isNull(parentNodeId)) { + if(UA_NodeId_isNull(referenceTypeId)) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Reference to parent cannot be null"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; + } + + retval = addParentRef(server, session, &node->nodeId, referenceTypeId, parentNodeId); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Adding reference to parent failed"); + goto cleanup; + } + } + + /* Add a hasTypeDefinition reference */ + if(node->nodeClass == UA_NODECLASS_VARIABLE || + node->nodeClass == UA_NODECLASS_OBJECT) { + UA_assert(type != NULL); /* see above */ + retval = addTypeDefRef(server, session, node, type); + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Adding a reference to the type " + "definition failed with error code %s", + UA_StatusCode_name(retval)); + } + + cleanup: + UA_Nodestore_release(server, node); + if(type) + UA_Nodestore_release(server, type); + if(retval != UA_STATUSCODE_GOOD) + UA_Server_deleteNode(server, *nodeId, UA_TRUE); + return retval; +} + +/* Create the node and add it to the nodestore. But don't typecheck and add + * references so far */ +static UA_StatusCode +AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext, + const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) { + UA_assert(outNewNodeId); + + /* Do not check access for server */ + if(session != &server->adminSession && server->config.accessControl.allowAddNode && + !server->config.accessControl.allowAddNode(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, item)) { + return UA_STATUSCODE_BADUSERACCESSDENIED; + } + + /* Check the namespaceindex */ + if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: 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"); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Create a node */ + 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 " + "in the nodestore"); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Fill the node attributes */ + node->context = nodeContext; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); + retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName); + retval |= UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data, + item->nodeAttributes.content.decoded.type); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Node could not create a node " + "with error code %s", UA_StatusCode_name(retval)); + UA_Nodestore_delete(server, node); + return retval; + } + + /* Use attributes from the typedefinition */ + if(!server->bootstrapNS0 && + (node->nodeClass == UA_NODECLASS_VARIABLE || + node->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, + (UA_VariableNode*)node, item); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Using attributes from the variable type " + "failed with error code %s", UA_StatusCode_name(retval)); + UA_Nodestore_delete(server, node); + return retval; + } + } + + /* Add the node to the nodestore */ + retval = UA_Nodestore_insert(server, node, outNewNodeId); + if(retval != UA_STATUSCODE_GOOD) + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Node could not add the new node " + "to the nodestore with error code %s", + UA_StatusCode_name(retval)); + return retval; +} + +/* Prepare the node, then add it to the nodestore */ +UA_StatusCode +Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext, + const UA_AddNodesItem *item, const UA_NodeId *parentNodeId, + const UA_NodeId *referenceTypeId, UA_NodeId *outNewNodeId) { + /* Create a temporary NodeId if none is returned */ + UA_NodeId newId; + if(!outNewNodeId) { + UA_NodeId_init(&newId); + outNewNodeId = &newId; + } + + /* Create the node and add it to the nodestore */ + UA_StatusCode retval = AddNode_raw(server, session, nodeContext, item, outNewNodeId); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Typecheck and add references to parent and type definition */ + retval = AddNode_typeCheckAddRefs(server, session, outNewNodeId, parentNodeId, + referenceTypeId, &item->typeDefinition.nodeId); + if(outNewNodeId == &newId) + UA_NodeId_deleteMembers(&newId); + return retval; +} + +/* Children, references, type-checking, constructors. */ +UA_StatusCode +Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + /* Get the node */ + const UA_Node *node = UA_Nodestore_get(server, nodeId); + if(!node) + return UA_STATUSCODE_BADNODEIDUNKNOWN; + + const UA_Node *type = NULL; + + /* Instantiate variables and objects */ + if(node->nodeClass == UA_NODECLASS_VARIABLE || + node->nodeClass == UA_NODECLASS_OBJECT) { + UA_NodeId *typeDefId; + retval = getTypeDef(server, node, &typeDefId); + if (retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Can not get type definition of node since it " + "has no 'hasTypeDef' reference"); + goto cleanup; + } + + /* Get the type node */ + type = UA_Nodestore_get(server, typeDefId); + if(!type) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Node type not found in nodestore"); + retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID; + goto cleanup; + } + + /* Add (mandatory) child nodes from the type definition */ + if(!server->bootstrapNS0) { + retval = addChildren(server, session, node, type); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Adding child nodes failed with error code %s", + UA_StatusCode_name(retval)); + goto cleanup; + } + } + } + + /* Call the constructor(s) */ + retval = callConstructors(server, session, node, type); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO_SESSION(server->config.logger, session, + "AddNodes: Calling the node constructor(s) failed " + "with status code %s", UA_StatusCode_name(retval)); + } + + cleanup: + if(type) + UA_Nodestore_release(server, type); + if(retval != UA_STATUSCODE_GOOD) + removeDeconstructedNode(server, session, node, true); + UA_Nodestore_release(server, node); + return retval; +} + +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, + &item->referenceTypeId, &result->addedNodeId); + if(result->statusCode != UA_STATUSCODE_GOOD) + return; + + /* AddNodes_finish */ + result->statusCode = + Operation_addNode_finish(server, session, &result->addedNodeId); + + /* If finishing failed, the node was deleted */ + if(result->statusCode != UA_STATUSCODE_GOOD) + UA_NodeId_deleteMembers(&result->addedNodeId); +} + +void +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"); + + if(server->config.maxNodesPerNodeManagement != 0 && + request->nodesToAddSize > server->config.maxNodesPerNodeManagement) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + 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]); +} + +UA_StatusCode +__UA_Server_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) { + /* Create the AddNodesItem */ + UA_AddNodesItem item; + UA_AddNodesItem_init(&item); + item.nodeClass = nodeClass; + item.requestedNewNodeId.nodeId = *requestedNewNodeId; + item.browseName = browseName; + 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; + + /* Call the normal addnodes service */ + UA_AddNodesResult result; + UA_AddNodesResult_init(&result); + Operation_addNode(server, &server->adminSession, nodeContext, &item, &result); + if(outNewNodeId) + *outNewNodeId = result.addedNodeId; + else + UA_NodeId_deleteMembers(&result.addedNodeId); + return result.statusCode; +} + +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) { + 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; + return Operation_addNode_begin(server, &server->adminSession, nodeContext, &item, + &parentNodeId, &referenceTypeId, outNewNodeId); +} + +UA_StatusCode +UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) { + return Operation_addNode_finish(server, &server->adminSession, &nodeId); +} + +/****************/ +/* Delete Nodes */ +/****************/ + +static void +Operation_deleteReference(UA_Server *server, UA_Session *session, void *context, + const UA_DeleteReferencesItem *item, UA_StatusCode *retval); + +/* Remove references to this node (in the other nodes) */ +static void +removeIncomingReferences(UA_Server *server, UA_Session *session, + const UA_Node *node) { + UA_DeleteReferencesItem item; + UA_DeleteReferencesItem_init(&item); + item.targetNodeId.nodeId = node->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->targetIdsSize; ++j) { + item.sourceNodeId = refs->targetIds[j].nodeId; + Operation_deleteReference(server, session, NULL, &item, &dummy); + } + } +} + +static void +deconstructNode(UA_Server *server, UA_Session *session, + const UA_Node *node) { + /* 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) + lifecycle->destructor(server, + &session->sessionId, session->sessionHandle, + &type->nodeId, type->context, + &node->nodeId, &context); + UA_Nodestore_release(server, type); + } + } + + /* Call the global destructor */ + if(server->config.nodeLifecycle.destructor) + server->config.nodeLifecycle.destructor(server, &session->sessionId, + session->sessionHandle, + &node->nodeId, context); +} + +static void +deleteNodeOperation(UA_Server *server, UA_Session *session, void *context, + const UA_DeleteNodesItem *item, UA_StatusCode *result); + +static void +removeChildren(UA_Server *server, UA_Session *session, + const UA_Node *node) { + /* 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; + bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD; + bd.resultMask = UA_BROWSERESULTMASK_NONE; + + 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; + + UA_DeleteNodesItem item; + item.deleteTargetReferences = true; + + /* 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; + item.nodeId = rd->nodeId.nodeId; + UA_StatusCode retval; + deleteNodeOperation(server, session, NULL, &item, &retval); + } + + UA_BrowseResult_deleteMembers(&br); +} + +static void +removeDeconstructedNode(UA_Server *server, UA_Session *session, + const UA_Node *node, UA_Boolean removeTargetRefs) { + /* Remove all children of the node */ + removeChildren(server, session, node); + + /* Remove references to the node (not the references going out, as the node + * will be deleted anyway) */ + if(removeTargetRefs) + removeIncomingReferences(server, session, node); + + /* Remove the node in the nodestore */ + UA_Nodestore_remove(server, &node->nodeId); +} + +static void +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 && + !server->config.accessControl.allowDeleteNode(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, item)) { + *result = UA_STATUSCODE_BADUSERACCESSDENIED; + return; + } + + const UA_Node *node = UA_Nodestore_get(server, &item->nodeId); + if(!node) { + *result = UA_STATUSCODE_BADNODEIDUNKNOWN; + 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"); + UA_Nodestore_release(server, node); + *result = UA_STATUSCODE_BADINTERNALERROR; + return; + } + + /* TODO: Check if the information model consistency is violated */ + /* TODO: Check if the node is a mandatory child of a parent */ + + deconstructNode(server, session, node); + removeDeconstructedNode(server, session, node, item->deleteTargetReferences); + UA_Nodestore_release(server, node); +} + +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"); + + if(server->config.maxNodesPerNodeManagement != 0 && + request->nodesToDeleteSize > server->config.maxNodesPerNodeManagement) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)deleteNodeOperation, NULL, + &request->nodesToDeleteSize, &UA_TYPES[UA_TYPES_DELETENODESITEM], + &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); +} + +UA_StatusCode +UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean deleteReferences) { + UA_DeleteNodesItem item; + item.deleteTargetReferences = deleteReferences; + item.nodeId = nodeId; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + deleteNodeOperation(server, &server->adminSession, NULL, &item, &retval); + return retval; +} + +/******************/ +/* Add References */ +/******************/ + +static UA_StatusCode +addOneWayReference(UA_Server *server, UA_Session *session, + UA_Node *node, const UA_AddReferencesItem *item) { + return UA_Node_addReference(node, item); +} + +static UA_StatusCode +deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, + const UA_DeleteReferencesItem *item) { + return UA_Node_deleteReference(node, item); +} + +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 */ + if(session != &server->adminSession && server->config.accessControl.allowAddReference && + !server->config.accessControl.allowAddReference(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, item)) { + *retval = UA_STATUSCODE_BADUSERACCESSDENIED; + return; + } + + /* Currently no expandednodeids are allowed */ + if(item->targetServerUri.length > 0) { + *retval = UA_STATUSCODE_BADNOTIMPLEMENTED; + return; + } + + /* Add the first direction */ + *retval = UA_Server_editNode(server, session, &item->sourceNodeId, + (UA_EditNodeCallback)addOneWayReference, + /* cast away const because callback uses const anyway */ + (UA_AddReferencesItem *)(uintptr_t)item); + UA_Boolean firstExisted = UA_FALSE; + if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) { + *retval = UA_STATUSCODE_GOOD; + firstExisted = UA_TRUE; + } else 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; + /* keep default secondItem.targetNodeClass = UA_NODECLASS_UNSPECIFIED */ + *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId, + (UA_EditNodeCallback)addOneWayReference, &secondItem); + + /* remove reference if the second direction failed */ + UA_Boolean secondExisted = UA_FALSE; + if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) { + *retval = UA_STATUSCODE_GOOD; + secondExisted = UA_TRUE; + } else 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 */ + 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) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing AddReferencesRequest"); + + if(server->config.maxNodesPerNodeManagement != 0 && + request->referencesToAddSize > server->config.maxNodesPerNodeManagement) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_addReference, NULL, + &request->referencesToAddSize, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], + &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); +} + +UA_StatusCode +UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, + const UA_NodeId refTypeId, + const UA_ExpandedNodeId targetId, + UA_Boolean isForward) { + UA_AddReferencesItem item; + UA_AddReferencesItem_init(&item); + item.sourceNodeId = sourceId; + item.referenceTypeId = refTypeId; + item.isForward = isForward; + item.targetNodeId = targetId; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + Operation_addReference(server, &server->adminSession, NULL, &item, &retval); + return retval; +} + +/*********************/ +/* Delete References */ +/*********************/ + +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 && + !server->config.accessControl.allowDeleteReference(server, &server->config.accessControl, + &session->sessionId, session->sessionHandle, item)) { + *retval = UA_STATUSCODE_BADUSERACCESSDENIED; + return; + } + + // 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 */ + (UA_DeleteReferencesItem *)(uintptr_t)item); + if(*retval != UA_STATUSCODE_GOOD) + return; + + if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0) + return; + + UA_DeleteReferencesItem secondItem; + UA_DeleteReferencesItem_init(&secondItem); + secondItem.isForward = !item->isForward; + secondItem.sourceNodeId = item->targetNodeId.nodeId; + secondItem.targetNodeId.nodeId = item->sourceNodeId; + secondItem.referenceTypeId = item->referenceTypeId; + *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId, + (UA_EditNodeCallback)deleteOneWayReference, + &secondItem); +} + +void +Service_DeleteReferences(UA_Server *server, UA_Session *session, + const UA_DeleteReferencesRequest *request, + UA_DeleteReferencesResponse *response) { + UA_LOG_DEBUG_SESSION(server->config.logger, session, + "Processing DeleteReferencesRequest"); + + if(server->config.maxNodesPerNodeManagement != 0 && + request->referencesToDeleteSize > server->config.maxNodesPerNodeManagement) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS; + return; + } + + response->responseHeader.serviceResult = + UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_deleteReference, NULL, + &request->referencesToDeleteSize, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], + &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]); +} + +UA_StatusCode +UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_ExpandedNodeId targetNodeId, + UA_Boolean deleteBidirectional) { + UA_DeleteReferencesItem item; + item.sourceNodeId = sourceNodeId; + item.referenceTypeId = referenceTypeId; + item.isForward = isForward; + item.targetNodeId = targetNodeId; + item.deleteBidirectional = deleteBidirectional; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + Operation_deleteReference(server, &server->adminSession, NULL, &item, &retval); + return retval; +} + +/**********************/ +/* Set Value Callback */ +/**********************/ + +static UA_StatusCode +setValueCallback(UA_Server *server, UA_Session *session, + UA_VariableNode *node, const UA_ValueCallback *callback) { + if(node->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) { + return UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback)setValueCallback, + /* cast away const because callback uses const anyway */ + (UA_ValueCallback *)(uintptr_t) &callback); +} + +/***************************************************/ +/* Special Handling of Variables with Data Sources */ +/***************************************************/ + +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, + void *nodeContext, UA_NodeId *outNewNodeId) { + UA_AddNodesItem item; + UA_AddNodesItem_init(&item); + item.nodeClass = UA_NODECLASS_VARIABLE; + item.requestedNewNodeId.nodeId = requestedNewNodeId; + item.browseName = browseName; + UA_ExpandedNodeId typeDefinitionId; + 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_NodeId newNodeId; + if(!outNewNodeId) { + newNodeId = UA_NODEID_NULL; + outNewNodeId = &newNodeId; + } + + /* Create the node and add it to the nodestore */ + UA_StatusCode retval = AddNode_raw(server, &server->adminSession, nodeContext, &item, outNewNodeId); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Set the data source */ + retval = UA_Server_setVariableNode_dataSource(server, *outNewNodeId, dataSource); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Typecheck and add references to parent and type definition */ + retval = AddNode_typeCheckAddRefs(server, &server->adminSession, outNewNodeId, &parentNodeId, + &referenceTypeId, &typeDefinition); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + + /* Call the constructors */ + retval = Operation_addNode_finish(server, &server->adminSession, outNewNodeId); + + cleanup: + if(outNewNodeId == &newNodeId) + UA_NodeId_deleteMembers(&newNodeId); + + return retval; +} + +static UA_StatusCode +setDataSource(UA_Server *server, UA_Session *session, + UA_VariableNode* node, const UA_DataSource *dataSource) { + if(node->nodeClass != UA_NODECLASS_VARIABLE) + return UA_STATUSCODE_BADNODECLASSINVALID; + if(node->valueSource == UA_VALUESOURCE_DATA) + UA_DataValue_deleteMembers(&node->value.data.value); + node->value.dataSource = *dataSource; + node->valueSource = UA_VALUESOURCE_DATASOURCE; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, + const UA_DataSource dataSource) { + return UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback)setDataSource, + /* casting away const because callback casts it back anyway */ + (UA_DataSource *) (uintptr_t)&dataSource); +} + +/************************************/ +/* Special Handling of Method Nodes */ +/************************************/ + +#ifdef UA_ENABLE_METHODCALLS + +static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPROPERTY}}; +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, + const UA_NodeId inputArgumentsRequestedNewNodeId, + UA_NodeId *inputArgumentsOutNewNodeId, + const size_t outputArgumentsSize, const UA_Argument *outputArguments, + const UA_NodeId outputArgumentsRequestedNewNodeId, + UA_NodeId *outputArgumentsOutNewNodeId) { + /* Browse to see which argument nodes exist */ + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = nodeId; + bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); + bd.includeSubtypes = false; + bd.browseDirection = UA_BROWSEDIRECTION_FORWARD; + bd.nodeClassMask = UA_NODECLASS_VARIABLE; + bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME; + + UA_BrowseResult br; + UA_BrowseResult_init(&br); + UA_UInt32 maxrefs = 0; + Operation_Browse(server, &server->adminSession, &maxrefs, &bd, &br); + + UA_StatusCode retval = br.statusCode; + if(retval != UA_STATUSCODE_GOOD) { + UA_Server_deleteNode(server, nodeId, true); + UA_BrowseResult_deleteMembers(&br); + return retval; + } + + /* Filter out the argument nodes */ + UA_NodeId inputArgsId = UA_NODEID_NULL; + UA_NodeId outputArgsId = UA_NODEID_NULL; + const UA_QualifiedName inputArgsName = UA_QUALIFIEDNAME(0, "InputArguments"); + const UA_QualifiedName outputArgsName = UA_QUALIFIEDNAME(0, "OutputArguments"); + for(size_t i = 0; i < br.referencesSize; i++) { + UA_ReferenceDescription *rd = &br.references[i]; + if(rd->browseName.namespaceIndex == 0 && + UA_String_equal(&rd->browseName.name, &inputArgsName.name)) + inputArgsId = rd->nodeId.nodeId; + else if(rd->browseName.namespaceIndex == 0 && + UA_String_equal(&rd->browseName.name, &outputArgsName.name)) + outputArgsId = rd->nodeId.nodeId; + } + + /* Add the Input Arguments VariableNode */ + if(inputArgumentsSize > 0 && UA_NodeId_isNull(&inputArgsId)) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + char *name = "InputArguments"; + attr.displayName = UA_LOCALIZEDTEXT("", name); + attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId; + attr.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 inputArgsSize32 = (UA_UInt32)inputArgumentsSize; + attr.arrayDimensions = &inputArgsSize32; + attr.arrayDimensionsSize = 1; + UA_Variant_setArray(&attr.value, (void*)(uintptr_t) inputArguments, + inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); + retval |= UA_Server_addVariableNode(server, inputArgumentsRequestedNewNodeId, nodeId, + hasproperty, UA_QUALIFIEDNAME(0, name), + propertytype, attr, NULL, &inputArgsId); + } + + /* Add the Output Arguments VariableNode */ + if(outputArgumentsSize > 0 && UA_NodeId_isNull(&outputArgsId)) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + char *name = "OutputArguments"; + attr.displayName = UA_LOCALIZEDTEXT("", name); + attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId; + attr.valueRank = UA_VALUERANK_ONE_DIMENSION; + UA_UInt32 outputArgsSize32 = (UA_UInt32)outputArgumentsSize; + attr.arrayDimensions = &outputArgsSize32; + attr.arrayDimensionsSize = 1; + UA_Variant_setArray(&attr.value, (void*)(uintptr_t) outputArguments, + outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); + retval |= UA_Server_addVariableNode(server, outputArgumentsRequestedNewNodeId, nodeId, + hasproperty, UA_QUALIFIEDNAME(0, name), + propertytype, attr, NULL, &outputArgsId); + } + + retval |= UA_Server_setMethodNode_callback(server, nodeId, method); + + /* Call finish to add the parent reference */ + retval |= Operation_addNode_finish(server, &server->adminSession, &nodeId); + + if(retval != UA_STATUSCODE_GOOD) { + UA_Server_deleteNode(server, nodeId, true); + UA_Server_deleteNode(server, inputArgsId, true); + UA_Server_deleteNode(server, outputArgsId, true); + } else { + if(inputArgumentsOutNewNodeId != NULL) { + UA_NodeId_copy(&inputArgsId, inputArgumentsOutNewNodeId); + } + if(outputArgumentsOutNewNodeId != NULL) { + UA_NodeId_copy(&outputArgsId, outputArgumentsOutNewNodeId); + } + } + UA_BrowseResult_deleteMembers(&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) { + return UA_Server_addMethodNodeEx_finish(server, nodeId, method, + inputArgumentsSize, inputArguments, UA_NODEID_NULL, NULL, + outputArgumentsSize, outputArguments, UA_NODEID_NULL, NULL); +} + +UA_StatusCode +UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId, + const UA_NodeId parentNodeId, + const UA_NodeId referenceTypeId, + const UA_QualifiedName browseName, + const UA_MethodAttributes attr, UA_MethodCallback method, + size_t inputArgumentsSize, const UA_Argument *inputArguments, + const UA_NodeId inputArgumentsRequestedNewNodeId, + UA_NodeId *inputArgumentsOutNewNodeId, + size_t outputArgumentsSize, const UA_Argument *outputArguments, + const UA_NodeId outputArgumentsRequestedNewNodeId, + UA_NodeId *outputArgumentsOutNewNodeId, + void *nodeContext, UA_NodeId *outNewNodeId) { + UA_AddNodesItem item; + UA_AddNodesItem_init(&item); + 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_NodeId newId; + if(!outNewNodeId) { + UA_NodeId_init(&newId); + outNewNodeId = &newId; + } + + UA_StatusCode retval = Operation_addNode_begin(server, &server->adminSession, nodeContext, + &item, &parentNodeId, &referenceTypeId, outNewNodeId); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + retval = UA_Server_addMethodNodeEx_finish(server, *outNewNodeId, method, + inputArgumentsSize, inputArguments, + inputArgumentsRequestedNewNodeId, + inputArgumentsOutNewNodeId, + outputArgumentsSize, outputArguments, + outputArgumentsRequestedNewNodeId, + outputArgumentsOutNewNodeId); + + if(outNewNodeId == &newId) + UA_NodeId_deleteMembers(&newId); + return retval; +} + +static UA_StatusCode +editMethodCallback(UA_Server *server, UA_Session* session, + UA_Node* node, void* handle) { + if(node->nodeClass != UA_NODECLASS_METHOD) + return UA_STATUSCODE_BADNODECLASSINVALID; + UA_MethodNode *mnode = (UA_MethodNode*) node; + mnode->method = (UA_MethodCallback)(uintptr_t)handle; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_setMethodNode_callback(UA_Server *server, + const UA_NodeId methodNodeId, + UA_MethodCallback methodCallback) { + return UA_Server_editNode(server, &server->adminSession, &methodNodeId, + (UA_EditNodeCallback)editMethodCallback, + (void*)(uintptr_t)methodCallback); +} + +#endif + +/************************/ +/* Lifecycle Management */ +/************************/ + +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; + } + + return UA_STATUSCODE_BADNODECLASSINVALID; +} + +UA_StatusCode +UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId, + UA_NodeTypeLifecycle lifecycle) { + return UA_Server_editNode(server, &server->adminSession, &nodeId, + (UA_EditNodeCallback)setNodeTypeLifecycle, + &lifecycle); +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + */ + +/* Enable POSIX features */ +#if !defined(_XOPEN_SOURCE) && !defined(_WRS_KERNEL) +# define _XOPEN_SOURCE 600 +#endif +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#endif +/* On older systems we need to define _BSD_SOURCE. + * _DEFAULT_SOURCE is an alias for that. */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif + + +#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) + +#ifdef _MSC_VER +# ifndef UNDER_CE +# include <io.h> //access +# define access _access +# endif +#else +# include <unistd.h> //access +# include <sys/time.h> // struct timeval +#endif + +#include <fcntl.h> +#include <errno.h> +#ifdef _WIN32 +# define CLOSESOCKET(S) closesocket((SOCKET)S) +# define errno__ WSAGetLastError() +#else +# define CLOSESOCKET(S) close(S) +# define errno__ errno +#endif + + +#ifdef UA_ENABLE_MULTITHREADING + +static void * +multicastWorkerLoop(UA_Server *server) { + struct timeval next_sleep = {.tv_sec = 0, .tv_usec = 0}; + volatile UA_Boolean *running = &server->mdnsRunning; + fd_set fds; + + while(*running) { + FD_ZERO(&fds); + FD_SET(server->mdnsSocket, &fds); + select(server->mdnsSocket + 1, &fds, 0, 0, &next_sleep); + + if(!*running) + break; + + unsigned short retVal = + mdnsd_step(server->mdnsDaemon, server->mdnsSocket, + FD_ISSET(server->mdnsSocket, &fds), true, &next_sleep); + if(retVal == 1) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast error: Can not read from socket. %s", errno_str)); + break; + } else if (retVal == 2) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast error: Can not write to socket. %s", errno_str)); + break; + } + } + return NULL; +} + +static UA_StatusCode +multicastListenStart(UA_Server* server) { + int err = pthread_create(&server->mdnsThread, NULL, + (void* (*)(void*))multicastWorkerLoop, server); + if(err != 0) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast error: Can not create multicast thread."); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +multicastListenStop(UA_Server* server) { + mdnsd_shutdown(server->mdnsDaemon); + // wake up select + write(server->mdnsSocket, "\0", 1); + if(pthread_join(server->mdnsThread, NULL)) { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast error: Can not stop thread."); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + return UA_STATUSCODE_BADNOTIMPLEMENTED; +} + +# endif /* UA_ENABLE_MULTITHREADING */ + +static UA_StatusCode +addMdnsRecordForNetworkLayer(UA_Server *server, const UA_String *appName, + const UA_ServerNetworkLayer* nl) { + UA_String hostname = UA_STRING_NULL; + UA_UInt16 port = 4840; + UA_String path = UA_STRING_NULL; + UA_StatusCode retval = UA_parseEndpointUrl(&nl->discoveryUrl, &hostname, + &port, &path); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Server url is invalid: %.*s", + (int)nl->discoveryUrl.length, nl->discoveryUrl.data); + return retval; + } + UA_Discovery_addRecord(server, appName, &hostname, port, + &path, UA_DISCOVERY_TCP, UA_TRUE, + server->config.serverCapabilities, + &server->config.serverCapabilitiesSize); + return UA_STATUSCODE_GOOD; +} + +void startMulticastDiscoveryServer(UA_Server *server) { + UA_String *appName = &server->config.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); + +# ifdef UA_ENABLE_MULTITHREADING + multicastListenStart(server); +# endif +} + +void stopMulticastDiscoveryServer(UA_Server *server) { + char hostname[256]; + if(gethostname(hostname, 255) == 0) { + UA_String hnString = UA_STRING(hostname); + UA_Discovery_removeRecord(server, &server->config.mdnsServerName, + &hnString, 4840, UA_TRUE); + } else { + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Could not get hostname for multicast discovery."); + } + +# ifdef UA_ENABLE_MULTITHREADING + multicastListenStop(server); +# else + // send out last package with TTL = 0 + iterateMulticastDiscoveryServer(server, NULL, UA_FALSE); +# endif +} + +/* All filter criteria must be fulfilled */ +static UA_Boolean +filterServerRecord(size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter, + serverOnNetwork_list_entry* current) { + 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; + } + return true; +} + +void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session, + const UA_FindServersOnNetworkRequest *request, + UA_FindServersOnNetworkResponse *response) { + /* Set LastCounterResetTime */ + UA_DateTime_copy(&server->serverOnNetworkRecordIdLastReset, + &response->lastCounterResetTime); + + /* Compute the max number of records to return */ + UA_UInt32 recordCount = 0; + if(request->startingRecordId < server->serverOnNetworkRecordIdCounter) + recordCount = server->serverOnNetworkRecordIdCounter - request->startingRecordId; + if(request->maxRecordsToReturn && recordCount > request->maxRecordsToReturn) + recordCount = UA_MIN(recordCount, request->maxRecordsToReturn); + if(recordCount == 0) { + response->serversSize = 0; + return; + } + + /* Iterate over all records and add to filtered list */ + UA_UInt32 filteredCount = 0; + UA_STACKARRAY(UA_ServerOnNetwork*, filtered, recordCount); + serverOnNetwork_list_entry* current; + LIST_FOREACH(current, &server->serverOnNetwork, pointers) { + if(filteredCount >= recordCount) + break; + if(current->serverOnNetwork.recordId < request->startingRecordId) + continue; + if(!filterServerRecord(request->serverCapabilityFilterSize, + request->serverCapabilityFilter, current)) + continue; + filtered[filteredCount++] = ¤t->serverOnNetwork; + } + + if(filteredCount == 0) + return; + + /* Allocate the array for the response */ + response->servers = + (UA_ServerOnNetwork*)UA_malloc(sizeof(UA_ServerOnNetwork)*filteredCount); + if(!response->servers) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return; + } + response->serversSize = filteredCount; + + /* Copy the server names */ + for(size_t i = 0; i < filteredCount; i++) + UA_ServerOnNetwork_copy(filtered[i], &response->servers[filteredCount-i-1]); +} + +void +UA_Discovery_update_MdnsForDiscoveryUrl(UA_Server *server, const UA_String *serverName, + const UA_MdnsDiscoveryConfiguration *mdnsConfig, + const UA_String *discoveryUrl, + UA_Boolean isOnline, UA_Boolean updateTxt) { + UA_String hostname = UA_STRING_NULL; + UA_UInt16 port = 4840; + UA_String path = UA_STRING_NULL; + UA_StatusCode retval = UA_parseEndpointUrl(discoveryUrl, &hostname, &port, &path); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_NETWORK, + "Server url invalid: %.*s", + (int)discoveryUrl->length, discoveryUrl->data); + return; + } + + if(!isOnline) { + UA_StatusCode removeRetval = + UA_Discovery_removeRecord(server, serverName, &hostname, + port, updateTxt); + if(removeRetval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Could not remove mDNS record for hostname %.*s.", + (int)serverName->length, serverName->data); + return; + } + + UA_String *capabilities = NULL; + size_t capabilitiesSize = 0; + if(mdnsConfig) { + capabilities = mdnsConfig->serverCapabilities; + capabilitiesSize = mdnsConfig->serverCapabilitiesSize; + } + + UA_StatusCode addRetval = + UA_Discovery_addRecord(server, serverName, &hostname, + port, &path, UA_DISCOVERY_TCP, updateTxt, + capabilities, &capabilitiesSize); + if(addRetval != UA_STATUSCODE_GOOD) + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Could not add mDNS record for hostname %.*s.", + (int)serverName->length, serverName->data); +} + +void +UA_Server_setServerOnNetworkCallback(UA_Server *server, + UA_Server_serverOnNetworkCallback cb, + void* data) { + server->serverOnNetworkCallback = cb; + server->serverOnNetworkCallbackData = data; +} + +static void +socket_mdns_set_nonblocking(int sockfd) { +#ifdef _WIN32 + u_long iMode = 1; + ioctlsocket(sockfd, FIONBIO, &iMode); +#else + int opts = fcntl(sockfd, F_GETFL); + fcntl(sockfd, F_SETFL, opts|O_NONBLOCK); +#endif +} + +/* Create multicast 224.0.0.251:5353 socket */ +#ifdef _WIN32 +static SOCKET +#else +static int +#endif +discovery_createMulticastSocket(void) { +#ifdef _WIN32 + SOCKET s; +#else + int s; +#endif + int flag = 1, ittl = 255; + struct sockaddr_in in; + struct ip_mreq mc; + char ttl = (char)255; // publish to complete net, not only subnet. See: + // https://docs.oracle.com/cd/E23824_01/html/821-1602/sockets-137.html + + memset(&in, 0, sizeof(in)); + in.sin_family = AF_INET; + in.sin_port = htons(5353); + in.sin_addr.s_addr = 0; + +#ifdef _WIN32 + if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) + return INVALID_SOCKET; +#else + if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + return -1; +#endif + +#ifdef SO_REUSEPORT + setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char *)&flag, sizeof(flag)); +#endif + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)); + if(bind(s, (struct sockaddr *)&in, sizeof(in))) { + CLOSESOCKET(s); +#ifdef _WIN32 + return INVALID_SOCKET; +#else + return -1; +#endif + } + + mc.imr_multiaddr.s_addr = inet_addr("224.0.0.251"); + mc.imr_interface.s_addr = htonl(INADDR_ANY); + setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mc, sizeof(mc)); + setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl)); + setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl, sizeof(ittl)); + + socket_mdns_set_nonblocking(s); + return s; +} + + +UA_StatusCode +initMulticastDiscoveryServer(UA_Server* server) { + server->mdnsDaemon = mdnsd_new(QCLASS_IN, 1000); +#ifdef _WIN32 + WORD wVersionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + WSAStartup(wVersionRequested, &wsaData); +#endif + +#ifdef _WIN32 + if((server->mdnsSocket = discovery_createMulticastSocket()) == INVALID_SOCKET) { +#else + if((server->mdnsSocket = discovery_createMulticastSocket()) < 0) { +#endif + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Could not create multicast socket. Error: %s", errno_str)); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + mdnsd_register_receive_callback(server->mdnsDaemon, + mdns_record_received, server); + return UA_STATUSCODE_GOOD; +} + +void destroyMulticastDiscoveryServer(UA_Server* server) { + mdnsd_shutdown(server->mdnsDaemon); + mdnsd_free(server->mdnsDaemon); +#ifdef _WIN32 + if(server->mdnsSocket != INVALID_SOCKET) { +#else + if(server->mdnsSocket >= 0) { +#endif + CLOSESOCKET(server->mdnsSocket); +#ifdef _WIN32 + server->mdnsSocket = INVALID_SOCKET; +#else + server->mdnsSocket = -1; +#endif + } +} + +static void +UA_Discovery_multicastConflict(char *name, int type, void *arg) { + // cppcheck-suppress unreadVariable + UA_Server *server = (UA_Server*) arg; + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS name conflict detected: " + "'%s' for type %d", name, type); +} + +/* Create a service domain with the format [servername]-[hostname]._opcua-tcp._tcp.local. */ +static void +createFullServiceDomain(char *outServiceDomain, size_t maxLen, + const UA_String *servername, const UA_String *hostname) { + size_t hostnameLen = hostname->length; + size_t servernameLen = servername->length; + + maxLen -= 24; /* the length we have remaining before the opc ua postfix and + * the trailing zero */ + + /* Can we use hostname and servername with full length? */ + if(hostnameLen + servernameLen + 1 > maxLen) { + if(servernameLen + 2 > maxLen) { + servernameLen = maxLen; + hostnameLen = 0; + } else { + hostnameLen = maxLen - servernameLen - 1; + } + } + + /* Copy into outServiceDomain */ + size_t offset = 0; + memcpy(&outServiceDomain[offset], servername->data, servernameLen); + offset += servernameLen; + if(hostnameLen > 0) { + memcpy(&outServiceDomain[offset], "-", 1); + ++offset; + memcpy(&outServiceDomain[offset], hostname->data, hostnameLen); + offset += hostnameLen; + } + memcpy(&outServiceDomain[offset], "._opcua-tcp._tcp.local.", 23); + offset += 23; + outServiceDomain[offset] = 0; +} + +/* Check if mDNS already has an entry for given hostname and port combination */ +static UA_Boolean +UA_Discovery_recordExists(UA_Server* server, const char* fullServiceDomain, + unsigned short port, const UA_DiscoveryProtocol protocol) { + // [servername]-[hostname]._opcua-tcp._tcp.local. 86400 IN SRV 0 5 port [hostname]. + mdns_record_t *r = mdnsd_get_published(server->mdnsDaemon, fullServiceDomain); + while(r) { + const mdns_answer_t *data = mdnsd_record_data(r); + if(data->type == QTYPE_SRV && (port == 0 || data->srv.port == port)) + return UA_TRUE; + r = mdnsd_record_next(r); + } + return UA_FALSE; +} + +static int +discovery_multicastQueryAnswer(mdns_answer_t *a, void *arg) { + UA_Server *server = (UA_Server*) arg; + if(a->type != QTYPE_PTR) + return 0; + + if(a->rdname == NULL) + return 0; + + /* Skip, if we already know about this server */ + UA_Boolean exists = + UA_Discovery_recordExists(server, a->rdname, 0, UA_DISCOVERY_TCP); + if(exists == UA_TRUE) + return 0; + + if(mdnsd_has_query(server->mdnsDaemon, a->rdname)) + return 0; + + UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER, + "mDNS send query for: %s SRV&TXT %s", a->name, a->rdname); + + mdnsd_query(server->mdnsDaemon, a->rdname, QTYPE_SRV, + discovery_multicastQueryAnswer, server); + mdnsd_query(server->mdnsDaemon, a->rdname, QTYPE_TXT, + discovery_multicastQueryAnswer, server); + return 0; +} + +UA_StatusCode +UA_Discovery_multicastQuery(UA_Server* server) { + mdnsd_query(server->mdnsDaemon, "_opcua-tcp._tcp.local.", + QTYPE_PTR,discovery_multicastQueryAnswer, server); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Discovery_addRecord(UA_Server *server, const UA_String *servername, + const UA_String *hostname, UA_UInt16 port, + const UA_String *path, const UA_DiscoveryProtocol protocol, + UA_Boolean createTxt, const UA_String* capabilites, + size_t *capabilitiesSize) { + if(!capabilitiesSize || (*capabilitiesSize > 0 && !capabilites)) + return UA_STATUSCODE_BADINVALIDARGUMENT; + + size_t hostnameLen = hostname->length; + size_t servernameLen = servername->length; + if(hostnameLen == 0 || servernameLen == 0) + return UA_STATUSCODE_BADOUTOFRANGE; + + // use a limit for the hostname length to make sure full string fits into 63 + // chars (limited by DNS spec) + if(hostnameLen+servernameLen + 1 > 63) { // include dash between servername-hostname + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: Combination of hostname+servername exceeds " + "maximum of 62 chars. It will be truncated."); + } else if(hostnameLen > 63) { + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: Hostname length exceeds maximum of 63 chars. " + "It will be truncated."); + } + + if(!server->mdnsMainSrvAdded) { + mdns_record_t *r = + mdnsd_shared(server->mdnsDaemon, "_services._dns-sd._udp.local.", + QTYPE_PTR, 600); + mdnsd_set_host(server->mdnsDaemon, r, "_opcua-tcp._tcp.local."); + server->mdnsMainSrvAdded = UA_TRUE; + } + + // [servername]-[hostname]._opcua-tcp._tcp.local. + char fullServiceDomain[63+24]; + createFullServiceDomain(fullServiceDomain, 63+24, servername, hostname); + + UA_Boolean exists = UA_Discovery_recordExists(server, fullServiceDomain, port, protocol); + if(exists == UA_TRUE) + return UA_STATUSCODE_GOOD; + + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: add record for domain: %s", fullServiceDomain); + + // _services._dns-sd._udp.local. PTR _opcua-tcp._tcp.local + + // check if there is already a PTR entry for the given service. + + // _opcua-tcp._tcp.local. PTR [servername]-[hostname]._opcua-tcp._tcp.local. + mdns_record_t *r = mdns_find_record(server->mdnsDaemon, QTYPE_PTR, + "_opcua-tcp._tcp.local.", fullServiceDomain); + if(!r) { + r = mdnsd_shared(server->mdnsDaemon, "_opcua-tcp._tcp.local.", QTYPE_PTR, 600); + mdnsd_set_host(server->mdnsDaemon, r, fullServiceDomain); + } + + /* The first 63 characters of the hostname (or less) */ + size_t maxHostnameLen = UA_MIN(hostnameLen, 63); + char localDomain[65]; + memcpy(localDomain, hostname->data, maxHostnameLen); + localDomain[maxHostnameLen] = '.'; + localDomain[maxHostnameLen+1] = '\0'; + + // [servername]-[hostname]._opcua-tcp._tcp.local. 86400 IN SRV 0 5 port [hostname]. + r = mdnsd_unique(server->mdnsDaemon, fullServiceDomain, QTYPE_SRV, 600, + UA_Discovery_multicastConflict, server); + mdnsd_set_srv(server->mdnsDaemon, r, 0, 0, port, localDomain); + + // A/AAAA record for all ip addresses. + // [servername]-[hostname]._opcua-tcp._tcp.local. A [ip]. + // [hostname]. A [ip]. + mdns_set_address_record(server, fullServiceDomain, localDomain); + + // TXT record: [servername]-[hostname]._opcua-tcp._tcp.local. TXT path=/ caps=NA,DA,... + UA_STACKARRAY(char, pathChars, path->length + 1); + if(createTxt) { + memcpy(pathChars, path->data, path->length); + pathChars[path->length] = 0; + mdns_create_txt(server, fullServiceDomain, pathChars, capabilites, + capabilitiesSize, UA_Discovery_multicastConflict); + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Discovery_removeRecord(UA_Server *server, const UA_String *servername, + const UA_String *hostname, UA_UInt16 port, + UA_Boolean removeTxt) { + // use a limit for the hostname length to make sure full string fits into 63 + // chars (limited by DNS spec) + size_t hostnameLen = hostname->length; + size_t servernameLen = servername->length; + if(hostnameLen == 0 || servernameLen == 0) + return UA_STATUSCODE_BADOUTOFRANGE; + + if(hostnameLen+servernameLen+1 > 63) { // include dash between servername-hostname + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: Combination of hostname+servername exceeds " + "maximum of 62 chars. It will be truncated."); + } + + // [servername]-[hostname]._opcua-tcp._tcp.local. + char fullServiceDomain[63 + 24]; + createFullServiceDomain(fullServiceDomain, 63+24, servername, hostname); + + UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: remove record for domain: %s", fullServiceDomain); + + // _opcua-tcp._tcp.local. PTR [servername]-[hostname]._opcua-tcp._tcp.local. + mdns_record_t *r = mdns_find_record(server->mdnsDaemon, QTYPE_PTR, + "_opcua-tcp._tcp.local.", fullServiceDomain); + if(!r) { + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: could not remove record. " + "PTR Record not found for domain: %s", fullServiceDomain); + return UA_STATUSCODE_BADNOTHINGTODO; + } + mdnsd_done(server->mdnsDaemon, r); + + // looks for [servername]-[hostname]._opcua-tcp._tcp.local. 86400 IN SRV 0 5 port hostname.local. + // and TXT record: [servername]-[hostname]._opcua-tcp._tcp.local. TXT path=/ caps=NA,DA,... + // and A record: [servername]-[hostname]._opcua-tcp._tcp.local. A [ip] + mdns_record_t *r2 = mdnsd_get_published(server->mdnsDaemon, fullServiceDomain); + if(!r2) { + UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast DNS: could not remove record. Record not " + "found for domain: %s", fullServiceDomain); + return UA_STATUSCODE_BADNOTHINGTODO; + } + + while(r2) { + const mdns_answer_t *data = mdnsd_record_data(r2); + mdns_record_t *next = mdnsd_record_next(r2); + if((removeTxt && data->type == QTYPE_TXT) || + (removeTxt && data->type == QTYPE_A) || + data->srv.port == port) { + mdnsd_done(server->mdnsDaemon, r2); + } + r2 = next; + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat, + UA_Boolean processIn) { + struct timeval next_sleep = { 0, 0 }; + unsigned short retval = mdnsd_step(server->mdnsDaemon, server->mdnsSocket, + processIn, true, &next_sleep); + if(retval == 1) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast error: Can not read from socket. %s", errno_str)); + return UA_STATUSCODE_BADNOCOMMUNICATION; + } else if(retval == 2) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, + "Multicast error: Can not write to socket. %s", errno_str)); + return UA_STATUSCODE_BADNOCOMMUNICATION; + } + + if(nextRepeat) + *nextRepeat = UA_DateTime_now() + + (UA_DateTime)((next_sleep.tv_sec * UA_DATETIME_SEC) + + (next_sleep.tv_usec * UA_DATETIME_USEC)); + return UA_STATUSCODE_GOOD; +} + +#endif /* defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2015-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015-2016 (c) Chris Iatrou + * Copyright 2015 (c) hfaham + * Copyright 2015-2017 (c) Florian Palm + * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2015 (c) Holger Jeromin + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016 (c) TorbenD + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2016 (c) Lykurg + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + +/********************/ +/* Client Lifecycle */ +/********************/ + +static void +UA_Client_init(UA_Client* client, UA_ClientConfig config) { + memset(client, 0, sizeof(UA_Client)); + /* TODO: Select policy according to the endpoint */ + UA_SecurityPolicy_None(&client->securityPolicy, NULL, UA_BYTESTRING_NULL, config.logger); + client->channel.securityPolicy = &client->securityPolicy; + client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE; + client->config = config; + if(client->config.stateCallback) + client->config.stateCallback(client, client->state); +} + +UA_Client * +UA_Client_new(UA_ClientConfig config) { + UA_Client *client = (UA_Client*)UA_malloc(sizeof(UA_Client)); + if(!client) + return NULL; + UA_Client_init(client, config); + return client; +} + +static void +UA_Client_deleteMembers(UA_Client* client) { + UA_Client_disconnect(client); + client->securityPolicy.deleteMembers(&client->securityPolicy); + UA_SecureChannel_deleteMembersCleanup(&client->channel); + UA_Connection_deleteMembers(&client->connection); + if(client->endpointUrl.data) + UA_String_deleteMembers(&client->endpointUrl); + UA_UserTokenPolicy_deleteMembers(&client->token); + UA_NodeId_deleteMembers(&client->authenticationToken); + if(client->username.data) + UA_String_deleteMembers(&client->username); + if(client->password.data) + UA_String_deleteMembers(&client->password); + + /* Delete the async service calls */ + UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN); + + /* Delete the subscriptions */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_Client_Subscriptions_clean(client); +#endif +} + +void +UA_Client_reset(UA_Client* client) { + UA_Client_deleteMembers(client); + UA_Client_init(client, client->config); +} + +void +UA_Client_delete(UA_Client* client) { + UA_Client_deleteMembers(client); + UA_free(client); +} + +UA_ClientState +UA_Client_getState(UA_Client *client) { + return client->state; +} + +void * +UA_Client_getContext(UA_Client *client) { + if(!client) + return NULL; + return client->config.clientContext; +} + +/****************/ +/* Raw Services */ +/****************/ + +/* For synchronous service calls. Execute async responses with a callback. When + * the response with the correct requestId turns up, return it via the + * SyncResponseDescription pointer. */ +typedef struct { + UA_Client *client; + UA_Boolean received; + UA_UInt32 requestId; + void *response; + const UA_DataType *responseType; +} SyncResponseDescription; + +/* For both synchronous and asynchronous service calls */ +static UA_StatusCode +sendSymmetricServiceRequest(UA_Client *client, const void *request, + const UA_DataType *requestType, UA_UInt32 *requestId) { + UA_StatusCode retval; + + /* If a message is pending in the chunk don't call UA_Client_manuallyRenewSecureChannel + * to prevent incomming message desynchronization */ + if(!client->connection.pendingMessage) { + /* Make sure we have a valid session */ + retval = UA_Client_manuallyRenewSecureChannel(client); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Adjusting the request header. The const attribute is violated, but we + * only touch the following members: */ + UA_RequestHeader *rr = (UA_RequestHeader*)(uintptr_t)request; + rr->authenticationToken = client->authenticationToken; /* cleaned up at the end */ + rr->timestamp = UA_DateTime_now(); + rr->requestHandle = ++client->requestHandle; + + /* Send the request */ + UA_UInt32 rqId = ++client->requestId; + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Sending a request of type %i", requestType->typeId.identifier.numeric); + + if (client->channel.nextSecurityToken.tokenId != 0) // Change to the new security token if the secure channel has been renewed. + UA_SecureChannel_revolveTokens(&client->channel); + retval = UA_SecureChannel_sendSymmetricMessage(&client->channel, rqId, UA_MESSAGETYPE_MSG, + rr, requestType); + UA_NodeId_init(&rr->authenticationToken); /* Do not return the token to the user */ + if(retval != UA_STATUSCODE_GOOD) + return retval; + + *requestId = rqId; + return UA_STATUSCODE_GOOD; +} + +static const UA_NodeId +serviceFaultId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_SERVICEFAULT_ENCODING_DEFAULTBINARY}}; + +/* Look for the async callback in the linked list, execute and delete it */ +static UA_StatusCode +processAsyncResponse(UA_Client *client, UA_UInt32 requestId, const UA_NodeId *responseTypeId, + const UA_ByteString *responseMessage, size_t *offset) { + /* Find the callback */ + AsyncServiceCall *ac; + LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) { + if(ac->requestId == requestId) + break; + } + if(!ac) + return UA_STATUSCODE_BADREQUESTHEADERINVALID; + + /* Allocate the response */ + UA_STACKARRAY(UA_Byte, responseBuf, ac->responseType->memSize); + void *response = (void*)(uintptr_t)&responseBuf[0]; /* workaround aliasing rules */ + + /* Verify the type of the 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)) { + UA_init(response, ac->responseType); + if(UA_NodeId_equal(responseTypeId, &serviceFaultId)) { + /* Decode as a ServiceFault, i.e. only the response header */ + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Received a ServiceFault response"); + responseType = &UA_TYPES[UA_TYPES_SERVICEFAULT]; + } else { + /* Close the connection */ + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Reply contains the wrong service response"); + retval = UA_STATUSCODE_BADCOMMUNICATIONERROR; + goto process; + } + } + + /* Decode the response */ + retval = UA_decodeBinary(responseMessage, offset, response, + responseType, 0, NULL); + + 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)); + ((UA_ResponseHeader*)response)->serviceResult = retval; + } + + /* Call the callback */ + if (ac->callback) + ac->callback(client, ac->userdata, requestId, response, ac->responseType); + UA_deleteMembers(response, ac->responseType); + + /* Remove the callback */ + LIST_REMOVE(ac, pointers); + UA_free(ac); + return retval; +} + +/* Processes the received service response. Either with an async callback or by + * decoding the message and returning it "upwards" in the + * SyncResponseDescription. */ +static UA_StatusCode +processServiceResponse(void *application, UA_SecureChannel *channel, + UA_MessageType messageType, UA_UInt32 requestId, + const UA_ByteString *message) { + SyncResponseDescription *rd = (SyncResponseDescription*)application; + + /* Must be OPN or MSG */ + if(messageType != UA_MESSAGETYPE_OPN && + messageType != UA_MESSAGETYPE_MSG) { + UA_LOG_TRACE_CHANNEL(rd->client->config.logger, channel, + "Invalid message type"); + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + + /* Has the SecureChannel timed out? + * TODO: Solve this for client and server together */ + if(rd->client->state >= UA_CLIENTSTATE_SECURECHANNEL && + (channel->securityToken.createdAt + + (channel->securityToken.revisedLifetime * UA_DATETIME_MSEC)) + < UA_DateTime_nowMonotonic()) + return UA_STATUSCODE_BADSECURECHANNELCLOSED; + + /* Decode the data type identifier of the response */ + size_t offset = 0; + UA_NodeId responseId; + UA_StatusCode retval = UA_NodeId_decodeBinary(message, &offset, &responseId); + if(retval != UA_STATUSCODE_GOOD) + goto finish; + + /* Got an asynchronous response. Don't expected a synchronous response + * (responseType NULL) or the id does not match. */ + if(!rd->responseType || requestId != rd->requestId) { + retval = processAsyncResponse(rd->client, requestId, &responseId, message, &offset); + goto finish; + } + + /* Got the synchronous response */ + rd->received = true; + + /* Forward declaration for the goto */ + UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, rd->responseType->binaryEncodingId); + + /* Check that the response type matches */ + if(!UA_NodeId_equal(&responseId, &expectedNodeId)) { + if(UA_NodeId_equal(&responseId, &serviceFaultId)) { + UA_LOG_INFO(rd->client->config.logger, UA_LOGCATEGORY_CLIENT, + "Received a ServiceFault response"); + UA_init(rd->response, rd->responseType); + retval = UA_decodeBinary(message, &offset, rd->response, + &UA_TYPES[UA_TYPES_SERVICEFAULT], 0, NULL); + } else { + /* Close the connection */ + UA_LOG_ERROR(rd->client->config.logger, UA_LOGCATEGORY_CLIENT, + "Reply contains the wrong service response"); + retval = UA_STATUSCODE_BADCOMMUNICATIONERROR; + } + goto finish; + } + + UA_LOG_DEBUG(rd->client->config.logger, UA_LOGCATEGORY_CLIENT, + "Decode a message of type %u", responseId.identifier.numeric); + + /* Decode the response */ + retval = UA_decodeBinary(message, &offset, rd->response, rd->responseType, + rd->client->config.customDataTypesSize, + rd->client->config.customDataTypes); + +finish: + UA_NodeId_deleteMembers(&responseId); + if(retval != UA_STATUSCODE_GOOD) { + if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) + retval = UA_STATUSCODE_BADRESPONSETOOLARGE; + UA_LOG_INFO(rd->client->config.logger, UA_LOGCATEGORY_CLIENT, + "Error receiving the response with status code %s", + UA_StatusCode_name(retval)); + + if(rd->response) { + UA_ResponseHeader *respHeader = (UA_ResponseHeader*)rd->response; + respHeader->serviceResult = retval; + } + } + return retval; +} + +/* Forward complete chunks directly to the securechannel */ +static UA_StatusCode +client_processChunk(void *application, UA_Connection *connection, UA_ByteString *chunk) { + SyncResponseDescription *rd = (SyncResponseDescription*)application; + return UA_SecureChannel_processChunk(&rd->client->channel, chunk, + processServiceResponse, + rd, UA_TRUE); +} + +/* Receive and process messages until a synchronous message arrives or the + * timout finishes */ +UA_StatusCode +receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *responseType, + UA_DateTime maxDate, UA_UInt32 *synchronousRequestId) { + /* Prepare the response and the structure we give into processServiceResponse */ + SyncResponseDescription rd = { client, false, 0, response, responseType }; + + /* Return upon receiving the synchronized response. All other responses are + * processed with a callback "in the background". */ + if(synchronousRequestId) + rd.requestId = *synchronousRequestId; + + UA_StatusCode retval; + do { + UA_DateTime now = UA_DateTime_nowMonotonic(); + + /* >= avoid timeout to be set to 0 */ + if(now >= maxDate) + return UA_STATUSCODE_GOODNONCRITICALTIMEOUT; + + /* round always to upper value to avoid timeout to be set to 0 + * if(maxDate - now) < (UA_DATETIME_MSEC/2) */ + UA_UInt32 timeout = (UA_UInt32)(((maxDate - now) + (UA_DATETIME_MSEC - 1)) / UA_DATETIME_MSEC); + + retval = UA_Connection_receiveChunksBlocking(&client->connection, &rd, client_processChunk, timeout); + + if(retval != UA_STATUSCODE_GOOD && retval != UA_STATUSCODE_GOODNONCRITICALTIMEOUT) { + if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED) + setClientState(client, UA_CLIENTSTATE_DISCONNECTED); + UA_Client_close(client); + break; + } + } while(!rd.received); + return retval; +} + +void +__UA_Client_Service(UA_Client *client, const void *request, + const UA_DataType *requestType, void *response, + const UA_DataType *responseType) { + UA_init(response, responseType); + UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response; + + /* Send the request */ + UA_UInt32 requestId; + UA_StatusCode retval = sendSymmetricServiceRequest(client, request, requestType, &requestId); + if(retval != UA_STATUSCODE_GOOD) { + if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) + respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE; + else + respHeader->serviceResult = retval; + UA_Client_close(client); + return; + } + + /* Retrieve the response */ + UA_DateTime maxDate = UA_DateTime_nowMonotonic() + + (client->config.timeout * UA_DATETIME_MSEC); + retval = receiveServiceResponse(client, response, responseType, maxDate, &requestId); + if(retval == UA_STATUSCODE_GOODNONCRITICALTIMEOUT) { + /* In synchronous service, if we have don't have a reply we need to close the connection */ + UA_Client_close(client); + retval = UA_STATUSCODE_BADCONNECTIONCLOSED; + } + if(retval != UA_STATUSCODE_GOOD) + respHeader->serviceResult = retval; +} + +void +UA_Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac, + UA_StatusCode statusCode) { + /* Create an empty response with the statuscode */ + UA_STACKARRAY(UA_Byte, responseBuf, ac->responseType->memSize); + void *resp = (void*)(uintptr_t)&responseBuf[0]; /* workaround aliasing rules */ + UA_init(resp, ac->responseType); + ((UA_ResponseHeader*)resp)->serviceResult = statusCode; + + if (ac->callback) + ac->callback(client, ac->userdata, ac->requestId, resp, ac->responseType); + + /* Clean up the response. Users might move data into it. For whatever reasons. */ + UA_deleteMembers(resp, ac->responseType); +} + +void UA_Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode) { + AsyncServiceCall *ac, *ac_tmp; + LIST_FOREACH_SAFE(ac, &client->asyncServiceCalls, pointers, ac_tmp) { + LIST_REMOVE(ac, pointers); + UA_Client_AsyncService_cancel(client, ac, statusCode); + UA_free(ac); + } +} + +UA_StatusCode +__UA_Client_AsyncServiceEx(UA_Client *client, const void *request, + const UA_DataType *requestType, + UA_ClientAsyncServiceCallback callback, + const UA_DataType *responseType, + void *userdata, UA_UInt32 *requestId, + UA_UInt32 timeout) { + /* Prepare the entry for the linked list */ + AsyncServiceCall *ac = (AsyncServiceCall*)UA_malloc(sizeof(AsyncServiceCall)); + if(!ac) + return UA_STATUSCODE_BADOUTOFMEMORY; + ac->callback = callback; + ac->responseType = responseType; + ac->userdata = userdata; + ac->timeout = timeout; + + /* Call the service and set the requestId */ + UA_StatusCode retval = sendSymmetricServiceRequest(client, request, requestType, &ac->requestId); + if(retval != UA_STATUSCODE_GOOD) { + ac->requestId = 0; + UA_Client_AsyncService_cancel(client, ac, UA_STATUSCODE_BADTIMEOUT); + UA_free(ac); + return retval; + } + + ac->start = UA_DateTime_nowMonotonic(); + + /* Store the entry for async processing */ + LIST_INSERT_HEAD(&client->asyncServiceCalls, ac, pointers); + if(requestId) + *requestId = ac->requestId; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +__UA_Client_AsyncService(UA_Client *client, const void *request, + const UA_DataType *requestType, + UA_ClientAsyncServiceCallback callback, + const UA_DataType *responseType, + void *userdata, UA_UInt32 *requestId) { + return __UA_Client_AsyncServiceEx(client, request, requestType, callback, + responseType, userdata, requestId, + client->config.timeout); +} + +static void +backgroundConnectivityCallback(UA_Client *client, void *userdata, + UA_UInt32 requestId, const UA_ReadResponse *response, + const UA_DataType *responseType) { + if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTIMEOUT) { + if (client->config.inactivityCallback) + client->config.inactivityCallback(client); + } + client->pendingConnectivityCheck = false; + client->lastConnectivityCheck = UA_DateTime_nowMonotonic(); +} + +static UA_StatusCode +UA_Client_backgroundConnectivity(UA_Client *client) { + if(!client->config.connectivityCheckInterval) + return UA_STATUSCODE_GOOD; + + if (client->pendingConnectivityCheck) + return UA_STATUSCODE_GOOD; + + UA_DateTime now = UA_DateTime_nowMonotonic(); + UA_DateTime nextDate = client->lastConnectivityCheck + (UA_DateTime)(client->config.connectivityCheckInterval * UA_DATETIME_MSEC); + + if(now <= nextDate) + return UA_STATUSCODE_GOOD; + + UA_ReadRequest request; + UA_ReadRequest_init(&request); + + UA_ReadValueId rvid; + UA_ReadValueId_init(&rvid); + rvid.attributeId = UA_ATTRIBUTEID_VALUE; + rvid.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); + + request.nodesToRead = &rvid; + request.nodesToReadSize = 1; + + UA_StatusCode retval = __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST], + (UA_ClientAsyncServiceCallback)backgroundConnectivityCallback, + &UA_TYPES[UA_TYPES_READRESPONSE], NULL, NULL); + + client->pendingConnectivityCheck = true; + + return retval; +} + +static void +asyncServiceTimeoutCheck(UA_Client *client) { + UA_DateTime now = UA_DateTime_nowMonotonic(); + + /* Timeout occurs, remove the callback */ + AsyncServiceCall *ac, *ac_tmp; + LIST_FOREACH_SAFE(ac, &client->asyncServiceCalls, pointers, ac_tmp) { + if (!ac->timeout) + continue; + + if (ac->start + (UA_DateTime)(ac->timeout * UA_DATETIME_MSEC) <= now) { + LIST_REMOVE(ac, pointers); + UA_Client_AsyncService_cancel(client, ac, UA_STATUSCODE_BADTIMEOUT); + UA_free(ac); + } + } +} + +UA_StatusCode +UA_Client_runAsync(UA_Client *client, UA_UInt16 timeout) { + /* TODO: Call repeated jobs that are scheduled */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_StatusCode retvalPublish = UA_Client_Subscriptions_backgroundPublish(client); + if (retvalPublish != UA_STATUSCODE_GOOD) + return retvalPublish; +#endif + UA_StatusCode retval = UA_Client_manuallyRenewSecureChannel(client); + if (retval != UA_STATUSCODE_GOOD) + return retval; + + retval = UA_Client_backgroundConnectivity(client); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + UA_DateTime maxDate = UA_DateTime_nowMonotonic() + (timeout * UA_DATETIME_MSEC); + retval = receiveServiceResponse(client, NULL, NULL, maxDate, NULL); + if(retval == UA_STATUSCODE_GOODNONCRITICALTIMEOUT) + retval = UA_STATUSCODE_GOOD; +#ifdef UA_ENABLE_SUBSCRIPTIONS + /* The inactivity check must be done after receiveServiceResponse */ + UA_Client_Subscriptions_backgroundPublishInactivityCheck(client); +#endif + asyncServiceTimeoutCheck(client); + return retval; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#define UA_MINMESSAGESIZE 8192 + + + /********************/ + /* Set client state */ + /********************/ +void +setClientState(UA_Client *client, UA_ClientState state) { + if(client->state != state) { + client->state = state; + if(client->config.stateCallback) + client->config.stateCallback(client, client->state); + } +} + +/***********************/ +/* Open the Connection */ +/***********************/ + +#define UA_BITMASK_MESSAGETYPE 0x00ffffff +#define UA_BITMASK_CHUNKTYPE 0xff000000 + +static UA_StatusCode +processACKResponse(void *application, UA_Connection *connection, UA_ByteString *chunk) { + UA_Client *client = (UA_Client*)application; + + /* Decode the message */ + size_t offset = 0; + UA_StatusCode retval; + UA_TcpMessageHeader messageHeader; + UA_TcpAcknowledgeMessage ackMessage; + retval = UA_TcpMessageHeader_decodeBinary(chunk, &offset, &messageHeader); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK, + "Decoding ACK message failed"); + return retval; + } + + // check if we got an error response from the server + UA_MessageType messageType = (UA_MessageType) + (messageHeader.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE); + UA_ChunkType chunkType = (UA_ChunkType) + (messageHeader.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE); + if (messageType == UA_MESSAGETYPE_ERR) { + // Header + ErrorMessage (error + reasonLength_field + length) + UA_StatusCode error = *(UA_StatusCode*)(&chunk->data[offset]); + UA_UInt32 len = *((UA_UInt32*)&chunk->data[offset + 4]); + UA_Byte *data = (UA_Byte*)&chunk->data[offset + 4+4]; + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_NETWORK, + "Received ERR response. %s - %.*s", UA_StatusCode_name(error), len, data); + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + if (chunkType != UA_CHUNKTYPE_FINAL) { + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + + retval |= UA_TcpAcknowledgeMessage_decodeBinary(chunk, &offset, &ackMessage); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK, + "Decoding ACK message failed"); + return retval; + } + + /* Store remote connection settings and adjust local configuration to not + * exceed the limits */ + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK, "Received ACK message"); + connection->remoteConf.maxChunkCount = ackMessage.maxChunkCount; /* may be zero -> unlimited */ + connection->remoteConf.maxMessageSize = ackMessage.maxMessageSize; /* may be zero -> unlimited */ + connection->remoteConf.protocolVersion = ackMessage.protocolVersion; + connection->remoteConf.sendBufferSize = ackMessage.sendBufferSize; + connection->remoteConf.recvBufferSize = ackMessage.receiveBufferSize; + if(connection->remoteConf.recvBufferSize < connection->localConf.sendBufferSize) + connection->localConf.sendBufferSize = connection->remoteConf.recvBufferSize; + if(connection->remoteConf.sendBufferSize < connection->localConf.recvBufferSize) + connection->localConf.recvBufferSize = connection->remoteConf.sendBufferSize; + connection->state = UA_CONNECTION_ESTABLISHED; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +HelAckHandshake(UA_Client *client) { + /* Get a buffer */ + UA_ByteString message; + UA_Connection *conn = &client->connection; + UA_StatusCode retval = conn->getSendBuffer(conn, UA_MINMESSAGESIZE, &message); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Prepare the HEL message and encode at offset 8 */ + UA_TcpHelloMessage hello; + UA_String_copy(&client->endpointUrl, &hello.endpointUrl); /* must be less than 4096 bytes */ + hello.maxChunkCount = conn->localConf.maxChunkCount; + hello.maxMessageSize = conn->localConf.maxMessageSize; + hello.protocolVersion = conn->localConf.protocolVersion; + hello.receiveBufferSize = conn->localConf.recvBufferSize; + hello.sendBufferSize = conn->localConf.sendBufferSize; + + UA_Byte *bufPos = &message.data[8]; /* skip the header */ + const UA_Byte *bufEnd = &message.data[message.length]; + retval = UA_TcpHelloMessage_encodeBinary(&hello, &bufPos, &bufEnd); + UA_TcpHelloMessage_deleteMembers(&hello); + + /* 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); + if(retval != UA_STATUSCODE_GOOD) { + conn->releaseSendBuffer(conn, &message); + return retval; + } + + /* Send the HEL message */ + message.length = messageHeader.messageSize; + retval = conn->send(conn, &message); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK, + "Sending HEL failed"); + return retval; + } + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK, + "Sent HEL message"); + + /* Loop until we have a complete chunk */ + retval = UA_Connection_receiveChunksBlocking(conn, client, processACKResponse, + client->config.timeout); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK, + "Receiving ACK message failed"); + if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED) + client->state = UA_CLIENTSTATE_DISCONNECTED; + UA_Client_close(client); + } + return retval; +} + +static void +processDecodedOPNResponse(UA_Client *client, UA_OpenSecureChannelResponse *response, UA_Boolean renew) { + /* Replace the token */ + if (renew) + client->channel.nextSecurityToken = response->securityToken; // Set the next token + else + client->channel.securityToken = response->securityToken; // Set initial token + + /* Replace the nonce */ + UA_ByteString_deleteMembers(&client->channel.remoteNonce); + client->channel.remoteNonce = response->serverNonce; + UA_ByteString_init(&response->serverNonce); + + if(client->channel.state == UA_SECURECHANNELSTATE_OPEN) + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, + "SecureChannel in the server renewed"); + else + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, + "Opened SecureChannel acknowledged by the server"); + + /* Response.securityToken.revisedLifetime is UInt32 we need to cast it to + * DateTime=Int64 we take 75% of lifetime to start renewing as described in + * standard */ + client->channel.state = UA_SECURECHANNELSTATE_OPEN; + client->nextChannelRenewal = UA_DateTime_nowMonotonic() + (UA_DateTime) + (client->channel.securityToken.revisedLifetime * (UA_Double)UA_DATETIME_MSEC * 0.75); +} + +static UA_StatusCode +openSecureChannel(UA_Client *client, UA_Boolean renew) { + /* Check if sc is still valid */ + if(renew && client->nextChannelRenewal > UA_DateTime_nowMonotonic()) + return UA_STATUSCODE_GOOD; + + UA_Connection *conn = &client->connection; + if(conn->state != UA_CONNECTION_ESTABLISHED) + return UA_STATUSCODE_BADSERVERNOTCONNECTED; + + /* Prepare the OpenSecureChannelRequest */ + UA_OpenSecureChannelRequest opnSecRq; + UA_OpenSecureChannelRequest_init(&opnSecRq); + opnSecRq.requestHeader.timestamp = UA_DateTime_now(); + opnSecRq.requestHeader.authenticationToken = client->authenticationToken; + if(renew) { + opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW; + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, + "Requesting to renew the SecureChannel"); + } else { + opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE; + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, + "Requesting to open a SecureChannel"); + } + opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE; + opnSecRq.clientNonce = client->channel.localNonce; + opnSecRq.requestedLifetime = client->config.secureChannelLifeTime; + + /* Send the OPN message */ + UA_UInt32 requestId = ++client->requestId; + UA_StatusCode retval = + UA_SecureChannel_sendAsymmetricOPNMessage(&client->channel, requestId, &opnSecRq, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, + "Sending OPN message failed with error %s", UA_StatusCode_name(retval)); + UA_Client_close(client); + return retval; + } + + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "OPN message sent"); + + /* Increase nextChannelRenewal to avoid that we re-start renewal when + * publish responses are received before the OPN response arrives. */ + client->nextChannelRenewal = UA_DateTime_nowMonotonic() + + (2 * ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC)); + + /* Receive / decrypt / decode the OPN response. Process async services in + * the background until the OPN response arrives. */ + UA_OpenSecureChannelResponse response; + retval = receiveServiceResponse(client, &response, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], + UA_DateTime_nowMonotonic() + + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC), + &requestId); + + if(retval != UA_STATUSCODE_GOOD) { + UA_Client_close(client); + return retval; + } + + processDecodedOPNResponse(client, &response, renew); + UA_OpenSecureChannelResponse_deleteMembers(&response); + return retval; +} + +static UA_StatusCode +activateSession(UA_Client *client) { + UA_ActivateSessionRequest request; + UA_ActivateSessionRequest_init(&request); + request.requestHeader.requestHandle = ++client->requestHandle; + request.requestHeader.timestamp = UA_DateTime_now(); + request.requestHeader.timeoutHint = 600000; + + //manual ExtensionObject encoding of the identityToken + if(client->authenticationMethod == UA_CLIENTAUTHENTICATION_NONE) { + UA_AnonymousIdentityToken* identityToken = UA_AnonymousIdentityToken_new(); + UA_AnonymousIdentityToken_init(identityToken); + UA_String_copy(&client->token.policyId, &identityToken->policyId); + request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED; + request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]; + request.userIdentityToken.content.decoded.data = identityToken; + } else { + UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new(); + UA_UserNameIdentityToken_init(identityToken); + UA_String_copy(&client->token.policyId, &identityToken->policyId); + UA_String_copy(&client->username, &identityToken->userName); + UA_String_copy(&client->password, &identityToken->password); + request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED; + request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]; + request.userIdentityToken.content.decoded.data = identityToken; + } + + UA_ActivateSessionResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST], + &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]); + + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "ActivateSession failed with error code %s", + UA_StatusCode_name(response.responseHeader.serviceResult)); + } + + UA_StatusCode retval = response.responseHeader.serviceResult; + UA_ActivateSessionRequest_deleteMembers(&request); + UA_ActivateSessionResponse_deleteMembers(&response); + return retval; +} + +/* Gets a list of endpoints. Memory is allocated for endpointDescription array */ +UA_StatusCode +UA_Client_getEndpointsInternal(UA_Client *client, size_t* endpointDescriptionsSize, + UA_EndpointDescription** endpointDescriptions) { + UA_GetEndpointsRequest request; + UA_GetEndpointsRequest_init(&request); + request.requestHeader.timestamp = UA_DateTime_now(); + request.requestHeader.timeoutHint = 10000; + // assume the endpointurl outlives the service call + request.endpointUrl = client->endpointUrl; + + UA_GetEndpointsResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], + &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); + + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_StatusCode retval = response.responseHeader.serviceResult; + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "GetEndpointRequest failed with error code %s", + UA_StatusCode_name(retval)); + UA_GetEndpointsResponse_deleteMembers(&response); + return retval; + } + *endpointDescriptions = response.endpoints; + *endpointDescriptionsSize = response.endpointsSize; + response.endpoints = NULL; + response.endpointsSize = 0; + UA_GetEndpointsResponse_deleteMembers(&response); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +getEndpoints(UA_Client *client) { + UA_EndpointDescription* endpointArray = NULL; + size_t endpointArraySize = 0; + UA_StatusCode retval = + UA_Client_getEndpointsInternal(client, &endpointArraySize, &endpointArray); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + UA_Boolean endpointFound = false; + UA_Boolean tokenFound = false; + UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); + UA_String binaryTransport = UA_STRING("http://opcfoundation.org/UA-Profile/" + "Transport/uatcp-uasc-uabinary"); + + // TODO: compare endpoint information with client->endpointUri + for(size_t i = 0; i < endpointArraySize; ++i) { + UA_EndpointDescription* endpoint = &endpointArray[i]; + /* look out for binary transport endpoints */ + /* Note: Siemens returns empty ProfileUrl, we will accept it as binary */ + if(endpoint->transportProfileUri.length != 0 && + !UA_String_equal(&endpoint->transportProfileUri, &binaryTransport)) + continue; + /* look out for an endpoint without security */ + if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone)) + continue; + + /* endpoint with no security found */ + endpointFound = true; + + /* look for a user token policy with an anonymous token */ + for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) { + UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j]; + + /* Usertokens also have a security policy... */ + if(userToken->securityPolicyUri.length > 0 && + !UA_String_equal(&userToken->securityPolicyUri, &securityNone)) + continue; + + /* UA_CLIENTAUTHENTICATION_NONE == UA_USERTOKENTYPE_ANONYMOUS + * UA_CLIENTAUTHENTICATION_USERNAME == UA_USERTOKENTYPE_USERNAME + * TODO: Check equivalence for other types when adding the support */ + if((int)client->authenticationMethod != (int)userToken->tokenType) + continue; + + /* Endpoint with matching usertokenpolicy found */ + tokenFound = true; + UA_UserTokenPolicy_deleteMembers(&client->token); + UA_UserTokenPolicy_copy(userToken, &client->token); + break; + } + } + + UA_Array_delete(endpointArray, endpointArraySize, + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); + + if(!endpointFound) { + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "No suitable endpoint found"); + retval = UA_STATUSCODE_BADINTERNALERROR; + } else if(!tokenFound) { + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "No suitable UserTokenPolicy found for the possible endpoints"); + retval = UA_STATUSCODE_BADINTERNALERROR; + } + return retval; +} + +static UA_StatusCode +createSession(UA_Client *client) { + UA_CreateSessionRequest request; + UA_CreateSessionRequest_init(&request); + + request.requestHeader.timestamp = UA_DateTime_now(); + request.requestHeader.timeoutHint = 10000; + UA_ByteString_copy(&client->channel.localNonce, &request.clientNonce); + request.requestedSessionTimeout = 1200000; + request.maxResponseMessageSize = UA_INT32_MAX; + UA_String_copy(&client->endpointUrl, &request.endpointUrl); + + UA_CreateSessionResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST], + &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]); + + UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken); + + UA_StatusCode retval = response.responseHeader.serviceResult; + UA_CreateSessionRequest_deleteMembers(&request); + UA_CreateSessionResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_connectInternal(UA_Client *client, const char *endpointUrl, + UA_Boolean endpointsHandshake, UA_Boolean createNewSession) { + if(client->state >= UA_CLIENTSTATE_CONNECTED) + return UA_STATUSCODE_GOOD; + UA_ChannelSecurityToken_init(&client->channel.securityToken); + client->channel.state = UA_SECURECHANNELSTATE_FRESH; + client->channel.sendSequenceNumber = 0; + client->requestId = 0; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + client->connection = + client->config.connectionFunc(client->config.localConnectionConfig, + endpointUrl, client->config.timeout, + client->config.logger); + if(client->connection.state != UA_CONNECTION_OPENING) { + retval = UA_STATUSCODE_BADCONNECTIONCLOSED; + goto cleanup; + } + + UA_String_deleteMembers(&client->endpointUrl); + client->endpointUrl = UA_STRING_ALLOC(endpointUrl); + if(!client->endpointUrl.data) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } + + /* Open a TCP connection */ + client->connection.localConf = client->config.localConnectionConfig; + retval = HelAckHandshake(client); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + setClientState(client, UA_CLIENTSTATE_CONNECTED); + + /* Open a SecureChannel. TODO: Select with endpoint */ + client->channel.connection = &client->connection; + retval = openSecureChannel(client, false); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + setClientState(client, UA_CLIENTSTATE_SECURECHANNEL); + + + /* Delete async service. TODO: Move this from connect to the disconnect/cleanup phase */ + UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN); + +#ifdef UA_ENABLE_SUBSCRIPTIONS + client->currentlyOutStandingPublishRequests = 0; +#endif + +// TODO: actually, reactivate an existing session is working, but currently republish is not implemented +// This option is disabled until we have a good implementation of the subscription recovery. + +#ifdef UA_SESSION_RECOVERY + /* Try to activate an existing Session for this SecureChannel */ + if((!UA_NodeId_equal(&client->authenticationToken, &UA_NODEID_NULL)) && (createNewSession)) { + retval = activateSession(client); + if(retval == UA_STATUSCODE_BADSESSIONIDINVALID) { + /* Could not recover an old session. Remove authenticationToken */ + UA_NodeId_deleteMembers(&client->authenticationToken); + } else { + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + setClientState(client, UA_CLIENTSTATE_SESSION_RENEWED); + return retval; + } + } else { + UA_NodeId_deleteMembers(&client->authenticationToken); + } +#else + UA_NodeId_deleteMembers(&client->authenticationToken); +#endif /* UA_SESSION_RECOVERY */ + + /* Get Endpoints */ + if(endpointsHandshake) { + retval = getEndpoints(client); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + } + + /* Create the Session for this SecureChannel */ + if(createNewSession) { + retval = createSession(client); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; +#ifdef UA_ENABLE_SUBSCRIPTIONS + /* A new session has been created. We need to clean up the subscriptions */ + UA_Client_Subscriptions_clean(client); +#endif + retval = activateSession(client); + if(retval != UA_STATUSCODE_GOOD) + goto cleanup; + setClientState(client, UA_CLIENTSTATE_SESSION); + } + + return retval; + +cleanup: + UA_Client_close(client); + return retval; +} + +UA_StatusCode +UA_Client_connect(UA_Client *client, const char *endpointUrl) { + return UA_Client_connectInternal(client, endpointUrl, UA_TRUE, UA_TRUE); +} + +UA_StatusCode +UA_Client_connect_username(UA_Client *client, const char *endpointUrl, + const char *username, const char *password) { + client->authenticationMethod = UA_CLIENTAUTHENTICATION_USERNAME; + client->username = UA_STRING_ALLOC(username); + client->password = UA_STRING_ALLOC(password); + return UA_Client_connect(client, endpointUrl); +} + +UA_StatusCode +UA_Client_manuallyRenewSecureChannel(UA_Client *client) { + UA_StatusCode retval = openSecureChannel(client, true); + if(retval != UA_STATUSCODE_GOOD) + UA_Client_close(client); + + return retval; +} + +/************************/ +/* Close the Connection */ +/************************/ + +static void +sendCloseSession(UA_Client *client) { + UA_CloseSessionRequest request; + UA_CloseSessionRequest_init(&request); + + request.requestHeader.timestamp = UA_DateTime_now(); + request.requestHeader.timeoutHint = 10000; + request.deleteSubscriptions = true; + 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); +} + +static void +sendCloseSecureChannel(UA_Client *client) { + UA_SecureChannel *channel = &client->channel; + UA_CloseSecureChannelRequest request; + UA_CloseSecureChannelRequest_init(&request); + request.requestHeader.requestHandle = ++client->requestHandle; + request.requestHeader.timestamp = UA_DateTime_now(); + request.requestHeader.timeoutHint = 10000; + request.requestHeader.authenticationToken = client->authenticationToken; + UA_SecureChannel_sendSymmetricMessage(channel, ++client->requestId, + UA_MESSAGETYPE_CLO, &request, + &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]); + UA_CloseSecureChannelRequest_deleteMembers(&request); + UA_SecureChannel_deleteMembersCleanup(&client->channel); +} + +UA_StatusCode +UA_Client_disconnect(UA_Client *client) { + /* Is a session established? */ + if(client->state >= UA_CLIENTSTATE_SESSION) { + client->state = UA_CLIENTSTATE_SECURECHANNEL; + sendCloseSession(client); + } + UA_NodeId_deleteMembers(&client->authenticationToken); + client->requestHandle = 0; + + /* Is a secure channel established? */ + if(client->state >= UA_CLIENTSTATE_SECURECHANNEL) { + client->state = UA_CLIENTSTATE_CONNECTED; + sendCloseSecureChannel(client); + } + + /* Close the TCP connection */ + if(client->connection.state != UA_CONNECTION_CLOSED) + client->connection.close(&client->connection); + +#ifdef UA_ENABLE_SUBSCRIPTIONS +// TODO REMOVE WHEN UA_SESSION_RECOVERY IS READY + /* We need to clean up the subscriptions */ + UA_Client_Subscriptions_clean(client); +#endif + + setClientState(client, UA_CLIENTSTATE_DISCONNECTED); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Client_close(UA_Client *client) { + client->requestHandle = 0; + + if(client->state >= UA_CLIENTSTATE_SECURECHANNEL) + UA_SecureChannel_deleteMembersCleanup(&client->channel); + + /* Close the TCP connection */ + if(client->connection.state != UA_CONNECTION_CLOSED) + client->connection.close(&client->connection); + +#ifdef UA_ENABLE_SUBSCRIPTIONS +// TODO REMOVE WHEN UA_SESSION_RECOVERY IS READY + /* We need to clean up the subscriptions */ + UA_Client_Subscriptions_clean(client); +#endif + + setClientState(client, UA_CLIENTSTATE_DISCONNECTED); + return UA_STATUSCODE_GOOD; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +UA_StatusCode +UA_Client_getEndpoints(UA_Client *client, const char *serverUrl, + size_t* endpointDescriptionsSize, + UA_EndpointDescription** endpointDescriptions) { + UA_Boolean connected = (client->state > UA_CLIENTSTATE_DISCONNECTED); + /* Client is already connected to a different server */ + if(connected && strncmp((const char*)client->endpointUrl.data, serverUrl, + client->endpointUrl.length) != 0) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + UA_StatusCode retval; + if(!connected) { + retval = UA_Client_connectInternal(client, serverUrl, UA_FALSE, UA_FALSE); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + retval = UA_Client_getEndpointsInternal(client, endpointDescriptionsSize, endpointDescriptions); + + if(!connected) + UA_Client_disconnect(client); + return retval; +} + +UA_StatusCode +UA_Client_findServers(UA_Client *client, const char *serverUrl, + size_t serverUrisSize, UA_String *serverUris, + size_t localeIdsSize, UA_String *localeIds, + size_t *registeredServersSize, + UA_ApplicationDescription **registeredServers) { + UA_Boolean connected = (client->state > UA_CLIENTSTATE_DISCONNECTED); + /* Client is already connected to a different server */ + if(connected && strncmp((const char*)client->endpointUrl.data, serverUrl, + client->endpointUrl.length) != 0) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + if(!connected) { + UA_StatusCode retval = UA_Client_connectInternal(client, serverUrl, UA_TRUE, UA_FALSE); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Prepare the request */ + UA_FindServersRequest request; + UA_FindServersRequest_init(&request); + request.serverUrisSize = serverUrisSize; + request.serverUris = serverUris; + request.localeIdsSize = localeIdsSize; + request.localeIds = localeIds; + + /* Send the request */ + UA_FindServersResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST], + &response, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]); + + /* Process the response */ + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + *registeredServersSize = response.serversSize; + *registeredServers = response.servers; + response.serversSize = 0; + response.servers = NULL; + } else { + *registeredServersSize = 0; + *registeredServers = NULL; + } + + /* Clean up */ + UA_FindServersResponse_deleteMembers(&response); + if(!connected) + UA_Client_disconnect(client); + return retval; +} + +UA_StatusCode +UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, + UA_UInt32 startingRecordId, UA_UInt32 maxRecordsToReturn, + size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter, + size_t *serverOnNetworkSize, UA_ServerOnNetwork **serverOnNetwork) { + UA_Boolean connected = (client->state > UA_CLIENTSTATE_DISCONNECTED); + /* Client is already connected to a different server */ + if(connected && strncmp((const char*)client->endpointUrl.data, serverUrl, + client->endpointUrl.length) != 0) { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + if(!connected) { + UA_StatusCode retval = UA_Client_connectInternal(client, serverUrl, UA_TRUE, UA_FALSE); + if(retval != UA_STATUSCODE_GOOD) + return retval; + } + + /* Prepare the request */ + UA_FindServersOnNetworkRequest request; + UA_FindServersOnNetworkRequest_init(&request); + request.startingRecordId = startingRecordId; + request.maxRecordsToReturn = maxRecordsToReturn; + request.serverCapabilityFilterSize = serverCapabilityFilterSize; + request.serverCapabilityFilter = serverCapabilityFilter; + + /* Send the request */ + UA_FindServersOnNetworkResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST], + &response, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]); + + /* Process the response */ + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + *serverOnNetworkSize = response.serversSize; + *serverOnNetwork = response.servers; + response.serversSize = 0; + response.servers = NULL; + } else { + *serverOnNetworkSize = 0; + *serverOnNetwork = NULL; + } + + /* Clean up */ + UA_FindServersOnNetworkResponse_deleteMembers(&response); + if(!connected) + UA_Client_disconnect(client); + return retval; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2017 (c) Florian Palm + * Copyright 2016 (c) Chris Iatrou + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +UA_StatusCode +UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, + UA_UInt16 *namespaceIndex) { + UA_ReadRequest request; + UA_ReadRequest_init(&request); + UA_ReadValueId id; + UA_ReadValueId_init(&id); + id.attributeId = UA_ATTRIBUTEID_VALUE; + id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY); + request.nodesToRead = &id; + request.nodesToReadSize = 1; + + UA_ReadResponse response = UA_Client_Service_read(client, request); + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) + retval = response.responseHeader.serviceResult; + else if(response.resultsSize != 1 || !response.results[0].hasValue) + retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; + else if(response.results[0].value.type != &UA_TYPES[UA_TYPES_STRING]) + retval = UA_STATUSCODE_BADTYPEMISMATCH; + + if(retval != UA_STATUSCODE_GOOD) { + UA_ReadResponse_deleteMembers(&response); + return retval; + } + + retval = UA_STATUSCODE_BADNOTFOUND; + UA_String *ns = (UA_String *)response.results[0].value.data; + for(size_t i = 0; i < response.results[0].value.arrayLength; ++i) { + if(UA_String_equal(namespaceUri, &ns[i])) { + *namespaceIndex = (UA_UInt16)i; + retval = UA_STATUSCODE_GOOD; + break; + } + } + + UA_ReadResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle) { + UA_BrowseRequest bReq; + UA_BrowseRequest_init(&bReq); + bReq.requestedMaxReferencesPerNode = 0; + bReq.nodesToBrowse = UA_BrowseDescription_new(); + bReq.nodesToBrowseSize = 1; + UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId); + bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything + bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH; + + UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq); + + UA_StatusCode retval = bResp.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + for(size_t i = 0; i < bResp.resultsSize; ++i) { + for(size_t j = 0; j < bResp.results[i].referencesSize; ++j) { + UA_ReferenceDescription *ref = &bResp.results[i].references[j]; + retval |= callback(ref->nodeId.nodeId, !ref->isForward, + ref->referenceTypeId, handle); + } + } + } + + UA_BrowseRequest_deleteMembers(&bReq); + UA_BrowseResponse_deleteMembers(&bResp); + return retval; +} + +/*******************/ +/* Node Management */ +/*******************/ + +UA_StatusCode +UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_String targetServerUri, + const UA_ExpandedNodeId targetNodeId, + UA_NodeClass targetNodeClass) { + UA_AddReferencesItem item; + UA_AddReferencesItem_init(&item); + item.sourceNodeId = sourceNodeId; + item.referenceTypeId = referenceTypeId; + item.isForward = isForward; + item.targetServerUri = targetServerUri; + item.targetNodeId = targetNodeId; + item.targetNodeClass = targetNodeClass; + UA_AddReferencesRequest request; + UA_AddReferencesRequest_init(&request); + request.referencesToAdd = &item; + request.referencesToAddSize = 1; + UA_AddReferencesResponse response = UA_Client_Service_addReferences(client, request); + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) { + UA_AddReferencesResponse_deleteMembers(&response); + return retval; + } + if(response.resultsSize != 1) { + UA_AddReferencesResponse_deleteMembers(&response); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + retval = response.results[0]; + UA_AddReferencesResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, + const UA_NodeId referenceTypeId, UA_Boolean isForward, + const UA_ExpandedNodeId targetNodeId, + UA_Boolean deleteBidirectional) { + UA_DeleteReferencesItem item; + UA_DeleteReferencesItem_init(&item); + item.sourceNodeId = sourceNodeId; + item.referenceTypeId = referenceTypeId; + item.isForward = isForward; + item.targetNodeId = targetNodeId; + item.deleteBidirectional = deleteBidirectional; + UA_DeleteReferencesRequest request; + UA_DeleteReferencesRequest_init(&request); + request.referencesToDelete = &item; + request.referencesToDeleteSize = 1; + UA_DeleteReferencesResponse response = UA_Client_Service_deleteReferences(client, request); + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) { + UA_DeleteReferencesResponse_deleteMembers(&response); + return retval; + } + if(response.resultsSize != 1) { + UA_DeleteReferencesResponse_deleteMembers(&response); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + retval = response.results[0]; + UA_DeleteReferencesResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId, + UA_Boolean deleteTargetReferences) { + UA_DeleteNodesItem item; + UA_DeleteNodesItem_init(&item); + item.nodeId = nodeId; + item.deleteTargetReferences = deleteTargetReferences; + UA_DeleteNodesRequest request; + UA_DeleteNodesRequest_init(&request); + request.nodesToDelete = &item; + request.nodesToDeleteSize = 1; + UA_DeleteNodesResponse response = UA_Client_Service_deleteNodes(client, request); + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) { + UA_DeleteNodesResponse_deleteMembers(&response); + return retval; + } + if(response.resultsSize != 1) { + UA_DeleteNodesResponse_deleteMembers(&response); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + retval = response.results[0]; + UA_DeleteNodesResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +__UA_Client_addNode(UA_Client *client, 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, UA_NodeId *outNewNodeId) { + UA_AddNodesRequest request; + UA_AddNodesRequest_init(&request); + UA_AddNodesItem item; + UA_AddNodesItem_init(&item); + item.parentNodeId.nodeId = parentNodeId; + item.referenceTypeId = referenceTypeId; + item.requestedNewNodeId.nodeId = requestedNewNodeId; + item.browseName = browseName; + item.nodeClass = nodeClass; + 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; // hack. is not written into. + request.nodesToAdd = &item; + request.nodesToAddSize = 1; + UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) { + UA_AddNodesResponse_deleteMembers(&response); + return retval; + } + + if(response.resultsSize != 1) { + UA_AddNodesResponse_deleteMembers(&response); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + /* Move the id of the created node */ + retval = response.results[0].statusCode; + if(retval == UA_STATUSCODE_GOOD && outNewNodeId) { + *outNewNodeId = response.results[0].addedNodeId; + UA_NodeId_init(&response.results[0].addedNodeId); + } + + UA_AddNodesResponse_deleteMembers(&response); + return retval; +} + +/********/ +/* Call */ +/********/ + +#ifdef UA_ENABLE_METHODCALLS + +UA_StatusCode +UA_Client_call(UA_Client *client, const UA_NodeId objectId, + const UA_NodeId methodId, size_t inputSize, + const UA_Variant *input, size_t *outputSize, + UA_Variant **output) { + /* Set up the request */ + UA_CallRequest request; + UA_CallRequest_init(&request); + UA_CallMethodRequest item; + UA_CallMethodRequest_init(&item); + item.methodId = methodId; + item.objectId = objectId; + item.inputArguments = (UA_Variant *)(void*)(uintptr_t)input; // cast const... + item.inputArgumentsSize = inputSize; + request.methodsToCall = &item; + request.methodsToCallSize = 1; + + /* Call the service */ + UA_CallResponse response = UA_Client_Service_call(client, request); + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + if(response.resultsSize == 1) + retval = response.results[0].statusCode; + else + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } + if(retval != UA_STATUSCODE_GOOD) { + UA_CallResponse_deleteMembers(&response); + return retval; + } + + /* Move the output arguments */ + if(output != NULL && outputSize != NULL) { + *output = response.results[0].outputArguments; + *outputSize = response.results[0].outputArgumentsSize; + response.results[0].outputArguments = NULL; + response.results[0].outputArgumentsSize = 0; + } + UA_CallResponse_deleteMembers(&response); + return retval; +} + +#endif + +/********************/ +/* Write Attributes */ +/********************/ + +UA_StatusCode +__UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, const void *in, + const UA_DataType *inDataType) { + if(!in) + return UA_STATUSCODE_BADTYPEMISMATCH; + + UA_WriteValue wValue; + UA_WriteValue_init(&wValue); + wValue.nodeId = *nodeId; + wValue.attributeId = attributeId; + if(attributeId == UA_ATTRIBUTEID_VALUE) + wValue.value.value = *(const UA_Variant*)in; + else + /* hack. is never written into. */ + UA_Variant_setScalar(&wValue.value.value, (void*)(uintptr_t)in, inDataType); + wValue.value.hasValue = true; + UA_WriteRequest wReq; + UA_WriteRequest_init(&wReq); + wReq.nodesToWrite = &wValue; + wReq.nodesToWriteSize = 1; + + UA_WriteResponse wResp = UA_Client_Service_write(client, wReq); + + UA_StatusCode retval = wResp.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + if(wResp.resultsSize == 1) + retval = wResp.results[0]; + else + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + UA_WriteResponse_deleteMembers(&wResp); + return retval; +} + +UA_StatusCode +UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId, + size_t newArrayDimensionsSize, + const UA_UInt32 *newArrayDimensions) { + if(!newArrayDimensions) + return UA_STATUSCODE_BADTYPEMISMATCH; + + UA_WriteValue wValue; + UA_WriteValue_init(&wValue); + wValue.nodeId = nodeId; + wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS; + UA_Variant_setArray(&wValue.value.value, (void*)(uintptr_t)newArrayDimensions, + newArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]); + wValue.value.hasValue = true; + UA_WriteRequest wReq; + UA_WriteRequest_init(&wReq); + wReq.nodesToWrite = &wValue; + wReq.nodesToWriteSize = 1; + + UA_WriteResponse wResp = UA_Client_Service_write(client, wReq); + + UA_StatusCode retval = wResp.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + if(wResp.resultsSize == 1) + retval = wResp.results[0]; + else + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } + UA_WriteResponse_deleteMembers(&wResp); + return retval; +} + +/*******************/ +/* Read Attributes */ +/*******************/ + +UA_StatusCode +__UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId, + UA_AttributeId attributeId, void *out, + const UA_DataType *outDataType) { + 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; + UA_ReadResponse response = UA_Client_Service_read(client, request); + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + if(response.resultsSize == 1) + retval = response.results[0].status; + else + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } + if(retval != UA_STATUSCODE_GOOD) { + UA_ReadResponse_deleteMembers(&response); + return retval; + } + + /* Set the StatusCode */ + UA_DataValue *res = response.results; + if(res->hasStatus) + retval = res->status; + + /* Return early of no value is given */ + if(!res->hasValue) { + if(retval == UA_STATUSCODE_GOOD) + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + UA_ReadResponse_deleteMembers(&response); + return retval; + } + + /* Copy value into out */ + if(attributeId == UA_ATTRIBUTEID_VALUE) { + memcpy(out, &res->value, sizeof(UA_Variant)); + UA_Variant_init(&res->value); + } else if(attributeId == UA_ATTRIBUTEID_NODECLASS) { + memcpy(out, (UA_NodeClass*)res->value.data, sizeof(UA_NodeClass)); + } else if(UA_Variant_isScalar(&res->value) && + res->value.type == outDataType) { + memcpy(out, res->value.data, res->value.type->memSize); + UA_free(res->value.data); + res->value.data = NULL; + } else { + retval = UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + UA_ReadResponse_deleteMembers(&response); + return retval; +} + +static UA_StatusCode +processReadArrayDimensionsResult(UA_ReadResponse *response, + UA_UInt32 **outArrayDimensions, + size_t *outArrayDimensionsSize) { + UA_StatusCode retval = response->responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) + return retval; + + if(response->resultsSize != 1) + return UA_STATUSCODE_BADUNEXPECTEDERROR; + + retval = response->results[0].status; + if(retval != UA_STATUSCODE_GOOD) + return retval; + + UA_DataValue *res = &response->results[0]; + if(!res->hasValue || + UA_Variant_isScalar(&res->value) || + res->value.type != &UA_TYPES[UA_TYPES_UINT32]) + return UA_STATUSCODE_BADUNEXPECTEDERROR; + + /* Move results */ + *outArrayDimensions = (UA_UInt32*)res->value.data; + *outArrayDimensionsSize = res->value.arrayLength; + res->value.data = NULL; + res->value.arrayLength = 0; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId, + size_t *outArrayDimensionsSize, + UA_UInt32 **outArrayDimensions) { + UA_ReadValueId item; + UA_ReadValueId_init(&item); + item.nodeId = nodeId; + item.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS; + UA_ReadRequest request; + UA_ReadRequest_init(&request); + request.nodesToRead = &item; + request.nodesToReadSize = 1; + + UA_ReadResponse response = UA_Client_Service_read(client, request); + UA_StatusCode retval = processReadArrayDimensionsResult(&response, outArrayDimensions, + outArrayDimensionsSize); + UA_ReadResponse_deleteMembers(&response); + return retval; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2015-2018 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016 (c) Sten Grüner + * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2016-2017 (c) Florian Palm + * Copyright 2017 (c) Frank Meerkötter + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ + +/*****************/ +/* Subscriptions */ +/*****************/ + +UA_CreateSubscriptionResponse UA_EXPORT +UA_Client_Subscriptions_create(UA_Client *client, + const UA_CreateSubscriptionRequest request, + void *subscriptionContext, + UA_Client_StatusChangeNotificationCallback statusChangeCallback, + UA_Client_DeleteSubscriptionCallback deleteCallback) { + UA_CreateSubscriptionResponse response; + UA_CreateSubscriptionResponse_init(&response); + + /* Allocate the internal representation */ + UA_Client_Subscription *newSub = (UA_Client_Subscription*) + UA_malloc(sizeof(UA_Client_Subscription)); + if(!newSub) { + response.responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + return response; + } + + /* Send the request as a synchronous service call */ + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], + &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]); + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_free(newSub); + return response; + } + + /* Prepare the internal representation */ + newSub->context = subscriptionContext; + newSub->subscriptionId = response.subscriptionId; + newSub->sequenceNumber = 0; + newSub->lastActivity = UA_DateTime_nowMonotonic(); + newSub->statusChangeCallback = statusChangeCallback; + newSub->deleteCallback = deleteCallback; + newSub->publishingInterval = response.revisedPublishingInterval; + newSub->maxKeepAliveCount = response.revisedMaxKeepAliveCount; + LIST_INIT(&newSub->monitoredItems); + LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry); + + return response; +} + +static UA_Client_Subscription * +findSubscription(const UA_Client *client, UA_UInt32 subscriptionId) { + UA_Client_Subscription *sub = NULL; + LIST_FOREACH(sub, &client->subscriptions, listEntry) { + if(sub->subscriptionId == subscriptionId) + break; + } + return sub; +} + +UA_ModifySubscriptionResponse UA_EXPORT +UA_Client_Subscriptions_modify(UA_Client *client, const UA_ModifySubscriptionRequest request) { + UA_ModifySubscriptionResponse response; + UA_ModifySubscriptionResponse_init(&response); + + /* Find the internal representation */ + UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + if(!sub) { + response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + return response; + } + + /* Call the service */ + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], + &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]); + + /* Adjust the internal representation */ + sub->publishingInterval = response.revisedPublishingInterval; + sub->maxKeepAliveCount = response.revisedMaxKeepAliveCount; + return response; +} + +static void +UA_Client_Subscription_deleteInternal(UA_Client *client, UA_Client_Subscription *sub) { + /* Remove the MonitoredItems */ + UA_Client_MonitoredItem *mon, *mon_tmp; + LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, mon_tmp) + UA_Client_MonitoredItem_remove(client, sub, mon); + + /* Call the delete callback */ + if(sub->deleteCallback) + sub->deleteCallback(client, sub->subscriptionId, sub->context); + + /* Remove */ + LIST_REMOVE(sub, listEntry); + UA_free(sub); +} + +UA_DeleteSubscriptionsResponse UA_EXPORT +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); + + /* temporary remove the subscriptions from the list */ + for(size_t i = 0; i < request.subscriptionIdsSize; i++) { + subs[i] = findSubscription(client, request.subscriptionIds[i]); + if (subs[i]) + LIST_REMOVE(subs[i], listEntry); + } + + /* Send the request */ + UA_DeleteSubscriptionsResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], + &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]); + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) + goto cleanup; + + if(request.subscriptionIdsSize != response.resultsSize) { + response.responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + + /* 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); + continue; + } + + if(!subs[i]) { + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_CLIENT, + "No internal representation of subscription %u", + request.subscriptionIds[i]); + continue; + } else { + LIST_INSERT_HEAD(&client->subscriptions, subs[i], listEntry); + } + + UA_Client_Subscription_deleteInternal(client, subs[i]); + } + + return response; + +cleanup: + for(size_t i = 0; i < request.subscriptionIdsSize; i++) { + if (subs[i]) { + LIST_INSERT_HEAD(&client->subscriptions, subs[i], listEntry); + } + } + return response; +} + +UA_StatusCode UA_EXPORT +UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId) { + UA_DeleteSubscriptionsRequest request; + UA_DeleteSubscriptionsRequest_init(&request); + request.subscriptionIds = &subscriptionId; + request.subscriptionIdsSize = 1; + + UA_DeleteSubscriptionsResponse response = + UA_Client_Subscriptions_delete(client, request); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) { + UA_DeleteSubscriptionsResponse_deleteMembers(&response); + return retval; + } + + if(response.resultsSize != 1) { + UA_DeleteSubscriptionsResponse_deleteMembers(&response); + return UA_STATUSCODE_BADINTERNALERROR; + } + + retval = response.results[0]; + UA_DeleteSubscriptionsResponse_deleteMembers(&response); + return retval; +} + +/******************/ +/* MonitoredItems */ +/******************/ + +void +UA_Client_MonitoredItem_remove(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, + mon->monitoredItemId, mon->context); + UA_free(mon); +} + +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_CreateMonitoredItemsResponse_init(response); + + if (!request->itemsToCreateSize) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + return; + } + + /* Fix clang warning */ + size_t itemsToCreateSize = request->itemsToCreateSize; + UA_Client_Subscription *sub = NULL; + + /* Allocate the memory for internal representations */ + UA_STACKARRAY(UA_Client_MonitoredItem*, mis, itemsToCreateSize); + memset(mis, 0, sizeof(void*) * itemsToCreateSize); + for(size_t i = 0; i < itemsToCreateSize; i++) { + mis[i] = (UA_Client_MonitoredItem*)UA_malloc(sizeof(UA_Client_MonitoredItem)); + if(!mis[i]) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; + goto cleanup; + } + } + + /* Get the subscription */ + sub = findSubscription(client, request->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + goto cleanup; + } + + /* Set the clientHandle */ + for(size_t i = 0; i < itemsToCreateSize; i++) + request->itemsToCreate[i].requestedParameters.clientHandle = ++(client->monitoredItemHandles); + + /* Call the service */ + __UA_Client_Service(client, request, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], + response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]); + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) + goto cleanup; + + if(response->resultsSize != itemsToCreateSize) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + goto cleanup; + } + + /* Add internally */ + for(size_t i = 0; i < 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; + continue; + } + + UA_Client_MonitoredItem *newMon = mis[i]; + newMon->clientHandle = request->itemsToCreate[i].requestedParameters.clientHandle; + newMon->monitoredItemId = response->results[i].monitoredItemId; + newMon->context = contexts[i]; + newMon->deleteCallback = deleteCallbacks[i]; + newMon->handler.dataChangeCallback = + (UA_Client_DataChangeNotificationCallback)(uintptr_t)handlingCallbacks[i]; + newMon->isEventMonitoredItem = + (request->itemsToCreate[i].itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER); + LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry); + } + + return; + + cleanup: + for(size_t i = 0; i < itemsToCreateSize; i++) { + if (deleteCallbacks[i]) { + if (sub) + deleteCallbacks[i](client, sub->subscriptionId, sub->context, 0, contexts[i]); + else + deleteCallbacks[i](client, 0, NULL, 0, contexts[i]); + } + if(mis[i]) + UA_free(mis[i]); + } +} + +UA_CreateMonitoredItemsResponse UA_EXPORT +UA_Client_MonitoredItems_createDataChanges(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_DataChangeNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks) { + UA_CreateMonitoredItemsResponse response; + __UA_Client_MonitoredItems_create(client, &request, contexts, + (void**)(uintptr_t)callbacks, deleteCallbacks, &response); + return response; +} + +UA_MonitoredItemCreateResult UA_EXPORT +UA_Client_MonitoredItems_createDataChange(UA_Client *client, UA_UInt32 subscriptionId, + UA_TimestampsToReturn timestampsToReturn, const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_DataChangeNotificationCallback callback, + UA_Client_DeleteMonitoredItemCallback deleteCallback) { + UA_CreateMonitoredItemsRequest request; + UA_CreateMonitoredItemsRequest_init(&request); + request.subscriptionId = subscriptionId; + request.timestampsToReturn = timestampsToReturn; + request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item; + request.itemsToCreateSize = 1; + UA_CreateMonitoredItemsResponse response = + UA_Client_MonitoredItems_createDataChanges(client, request, &context, + &callback, &deleteCallback); + UA_MonitoredItemCreateResult result; + UA_MonitoredItemCreateResult_init(&result); + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) + result.statusCode = response.responseHeader.serviceResult; + + if(result.statusCode == UA_STATUSCODE_GOOD && + response.resultsSize != 1) + result.statusCode = UA_STATUSCODE_BADINTERNALERROR; + + if(result.statusCode == UA_STATUSCODE_GOOD) + UA_MonitoredItemCreateResult_copy(&response.results[0] , &result); + UA_CreateMonitoredItemsResponse_deleteMembers(&response); + return result; +} + +UA_CreateMonitoredItemsResponse UA_EXPORT +UA_Client_MonitoredItems_createEvents(UA_Client *client, + const UA_CreateMonitoredItemsRequest request, void **contexts, + UA_Client_EventNotificationCallback *callbacks, + UA_Client_DeleteMonitoredItemCallback *deleteCallbacks) { + UA_CreateMonitoredItemsResponse response; + __UA_Client_MonitoredItems_create(client, &request, contexts, + (void**)(uintptr_t)callbacks, deleteCallbacks, &response); + return response; +} + +UA_MonitoredItemCreateResult UA_EXPORT +UA_Client_MonitoredItems_createEvent(UA_Client *client, UA_UInt32 subscriptionId, + UA_TimestampsToReturn timestampsToReturn, const UA_MonitoredItemCreateRequest item, + void *context, UA_Client_EventNotificationCallback callback, + UA_Client_DeleteMonitoredItemCallback deleteCallback) { + UA_CreateMonitoredItemsRequest request; + UA_CreateMonitoredItemsRequest_init(&request); + request.subscriptionId = subscriptionId; + request.timestampsToReturn = timestampsToReturn; + request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item; + request.itemsToCreateSize = 1; + UA_CreateMonitoredItemsResponse response = + UA_Client_MonitoredItems_createEvents(client, request, &context, + &callback, &deleteCallback); + UA_MonitoredItemCreateResult result; + UA_MonitoredItemCreateResult_copy(response.results , &result); + UA_CreateMonitoredItemsResponse_deleteMembers(&response); + return result; +} + +UA_DeleteMonitoredItemsResponse UA_EXPORT +UA_Client_MonitoredItems_delete(UA_Client *client, const UA_DeleteMonitoredItemsRequest request) { + /* Send the request */ + UA_DeleteMonitoredItemsResponse response; + __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], + &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]); + if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) + return response; + + UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId); + if(!sub) { + UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_CLIENT, + "No internal representation of subscription %u", + request.subscriptionId); + return response; + } + + /* Loop over deleted MonitoredItems */ + for(size_t i = 0; i < response.resultsSize; i++) { + if(response.results[i] != UA_STATUSCODE_GOOD && + response.results[i] != UA_STATUSCODE_BADMONITOREDITEMIDINVALID) { + continue; + } + +#ifndef __clang_analyzer__ + /* Delete the internal representation */ + UA_Client_MonitoredItem *mon; + LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { + if(mon->monitoredItemId == request.monitoredItemIds[i]) { + UA_Client_MonitoredItem_remove(client, sub, mon); + break; + } + } +#endif + } + + return response; +} + +UA_StatusCode UA_EXPORT +UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId, UA_UInt32 monitoredItemId) { + UA_DeleteMonitoredItemsRequest request; + UA_DeleteMonitoredItemsRequest_init(&request); + request.subscriptionId = subscriptionId; + request.monitoredItemIds = &monitoredItemId; + request.monitoredItemIdsSize = 1; + + UA_DeleteMonitoredItemsResponse response = + UA_Client_MonitoredItems_delete(client, request); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval != UA_STATUSCODE_GOOD) { + UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + return retval; + } + + if(response.resultsSize != 1) { + UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + return UA_STATUSCODE_BADINTERNALERROR; + } + + retval = response.results[0]; + UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + return retval; +} + +/*************************************/ +/* Async Processing of Notifications */ +/*************************************/ + +/* Assume the request is already initialized */ +UA_StatusCode +UA_Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request) { + /* Count acks */ + UA_Client_NotificationsAckNumber *ack; + LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry) + ++request->subscriptionAcknowledgementsSize; + + /* Create the array. Returns a sentinel pointer if the length is zero. */ + request->subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement*) + UA_Array_new(request->subscriptionAcknowledgementsSize, + &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT]); + if(!request->subscriptionAcknowledgements) { + request->subscriptionAcknowledgementsSize = 0; + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + size_t i = 0; + UA_Client_NotificationsAckNumber *ack_tmp; + LIST_FOREACH_SAFE(ack, &client->pendingNotificationsAcks, listEntry, ack_tmp) { + request->subscriptionAcknowledgements[i].sequenceNumber = ack->subAck.sequenceNumber; + request->subscriptionAcknowledgements[i].subscriptionId = ack->subAck.subscriptionId; + ++i; + LIST_REMOVE(ack, listEntry); + UA_free(ack); + } + return UA_STATUSCODE_GOOD; +} + +/* According to OPC Unified Architecture, Part 4 5.13.1.1 i) */ +/* The value 0 is never used for the sequence number */ +static UA_UInt32 +UA_Client_Subscriptions_nextSequenceNumber(UA_UInt32 sequenceNumber) { + UA_UInt32 nextSequenceNumber = sequenceNumber + 1; + if(nextSequenceNumber == 0) + nextSequenceNumber = 1; + return nextSequenceNumber; +} + +static void +processDataChangeNotification(UA_Client *client, UA_Client_Subscription *sub, + UA_DataChangeNotification *dataChangeNotification) { + for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) { + UA_MonitoredItemNotification *min = &dataChangeNotification->monitoredItems[j]; + + /* Find the MonitoredItem */ + UA_Client_MonitoredItem *mon; + LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { + if(mon->clientHandle == min->clientHandle) + break; + } + + if(!mon) { + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Could not process a notification with clienthandle %u on subscription %u", + 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."); + continue; + } + + mon->handler.dataChangeCallback(client, sub->subscriptionId, sub->context, + mon->monitoredItemId, mon->context, + &min->value); + } +} + +static void +processEventNotification(UA_Client *client, UA_Client_Subscription *sub, + UA_EventNotificationList *eventNotificationList) { + for(size_t j = 0; j < eventNotificationList->eventsSize; ++j) { + UA_EventFieldList *eventFieldList = &eventNotificationList->events[j]; + + /* Find the MonitoredItem */ + UA_Client_MonitoredItem *mon; + LIST_FOREACH(mon, &sub->monitoredItems, listEntry) { + if(mon->monitoredItemId == eventFieldList->clientHandle) + break; + } + + if(!mon) { + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Could not process a notification with clienthandle %u on subscription %u", + eventFieldList->clientHandle, sub->subscriptionId); + continue; + } + + if(!mon->isEventMonitoredItem) { + UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT, + "MonitoredItem is configured for DataChanges. But received a " + "EventNotification."); + continue; + } + + mon->handler.eventCallback(client, sub->subscriptionId, sub->context, + mon->monitoredItemId, mon->context, + eventFieldList->eventFieldsSize, + eventFieldList->eventFields); + } +} + +static void +processNotificationMessage(UA_Client *client, UA_Client_Subscription *sub, + UA_ExtensionObject *msg) { + if(msg->encoding != UA_EXTENSIONOBJECT_DECODED) + return; + + /* Handle DataChangeNotification */ + if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) { + UA_DataChangeNotification *dataChangeNotification = + (UA_DataChangeNotification *)msg->content.decoded.data; + processDataChangeNotification(client, sub, dataChangeNotification); + return; + } + + /* Handle EventNotification */ + if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) { + UA_EventNotificationList *eventNotificationList = + (UA_EventNotificationList *)msg->content.decoded.data; + processEventNotification(client, sub, eventNotificationList); + return; + } + + /* Handle StatusChangeNotification */ + if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]) { + if(sub->statusChangeCallback) { + sub->statusChangeCallback(client, sub->subscriptionId, sub->context, + (UA_StatusChangeNotification*)msg->content.decoded.data); + } else { + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Dropped a StatusChangeNotification since no callback is registered"); + } + return; + } + + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Unknown notification message type"); +} + +void +UA_Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequest *request, + UA_PublishResponse *response) { + UA_NotificationMessage *msg = &response->notificationMessage; + + client->currentlyOutStandingPublishRequests--; + + if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS) { + if(client->config.outStandingPublishRequests > 1) { + client->config.outStandingPublishRequests--; + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Too many publishrequest, reduce outStandingPublishRequests to %d", + client->config.outStandingPublishRequests); + } else { + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Too many publishrequest when outStandingPublishRequests = 1"); + UA_Client_Subscriptions_deleteSingle(client, response->subscriptionId); + } + return; + } + + if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSHUTDOWN) + return; + + if(!LIST_FIRST(&client->subscriptions)) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION; + return; + } + + if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED) { + if(client->state >= UA_CLIENTSTATE_SESSION) { + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Received Publish Response with code %s", + UA_StatusCode_name(response->responseHeader.serviceResult)); + } + return; + } + + if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONIDINVALID) { + UA_Client_close(client); /* TODO: This should be handled before the process callback */ + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Received BadSessionIdInvalid"); + return; + } + + if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Received Publish Response with code %s", + UA_StatusCode_name(response->responseHeader.serviceResult)); + return; + } + + UA_Client_Subscription *sub = findSubscription(client, response->subscriptionId); + if(!sub) { + response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Received Publish Response for a non-existant subscription"); + return; + } + + sub->lastActivity = UA_DateTime_nowMonotonic(); + + /* 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 %u but got %u", + 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_close(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. */ + if (msg->notificationDataSize) + sub->sequenceNumber = msg->sequenceNumber; + + /* Process the notification messages */ + for(size_t k = 0; k < msg->notificationDataSize; ++k) + processNotificationMessage(client, sub, &msg->notificationData[k]); + + /* Add to the list of pending acks */ + for(size_t i = 0; i < response->availableSequenceNumbersSize; i++) { + if(response->availableSequenceNumbers[i] != msg->sequenceNumber) + continue; + UA_Client_NotificationsAckNumber *tmpAck = (UA_Client_NotificationsAckNumber*) + UA_malloc(sizeof(UA_Client_NotificationsAckNumber)); + if(!tmpAck) { + UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Not enough memory to store the acknowledgement for a publish " + "message on subscription %u", sub->subscriptionId); + break; + } + tmpAck->subAck.sequenceNumber = msg->sequenceNumber; + tmpAck->subAck.subscriptionId = sub->subscriptionId; + LIST_INSERT_HEAD(&client->pendingNotificationsAcks, tmpAck, listEntry); + break; + } +} + +static void +processPublishResponseAsync(UA_Client *client, void *userdata, UA_UInt32 requestId, + void *response, const UA_DataType *responseType) { + UA_PublishRequest *req = (UA_PublishRequest*)userdata; + UA_PublishResponse *res = (UA_PublishResponse*)response; + + /* Process the response */ + UA_Client_Subscriptions_processPublishResponse(client, req, res); + + /* Delete the cached request */ + UA_PublishRequest_delete(req); + + /* Fill up the outstanding publish requests */ + UA_Client_Subscriptions_backgroundPublish(client); +} + +void +UA_Client_Subscriptions_clean(UA_Client *client) { + UA_Client_NotificationsAckNumber *n, *tmp; + LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) { + LIST_REMOVE(n, listEntry); + UA_free(n); + } + + UA_Client_Subscription *sub, *tmps; + LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps) + UA_Client_Subscription_deleteInternal(client, sub); /* force local removal */ + + client->monitoredItemHandles = 0; +} + +void +UA_Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client) { + if(client->state < UA_CLIENTSTATE_SESSION) + return; + + /* Is the lack of responses the client's fault? */ + if(client->currentlyOutStandingPublishRequests == 0) + return; + + UA_Client_Subscription *sub; + LIST_FOREACH(sub, &client->subscriptions, listEntry) { + UA_DateTime maxSilence = (UA_DateTime) + ((sub->publishingInterval * sub->maxKeepAliveCount) + + client->config.timeout) * UA_DATETIME_MSEC; + if(maxSilence + sub->lastActivity < UA_DateTime_nowMonotonic()) { + /* Reset activity */ + sub->lastActivity = UA_DateTime_nowMonotonic(); + + if(client->config.subscriptionInactivityCallback) + client->config.subscriptionInactivityCallback(client, sub->subscriptionId, sub->context); + UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT, + "Inactivity for Subscription %u.", sub->subscriptionId); + } + } +} + +UA_StatusCode +UA_Client_Subscriptions_backgroundPublish(UA_Client *client) { + if(client->state < UA_CLIENTSTATE_SESSION) + return UA_STATUSCODE_BADSERVERNOTCONNECTED; + + /* The session must have at least one subscription */ + if(!LIST_FIRST(&client->subscriptions)) + return UA_STATUSCODE_GOOD; + + while(client->currentlyOutStandingPublishRequests < client->config.outStandingPublishRequests) { + UA_PublishRequest *request = UA_PublishRequest_new(); + if (!request) + return UA_STATUSCODE_BADOUTOFMEMORY; + + request->requestHeader.timeoutHint=60000; + UA_StatusCode retval = UA_Client_preparePublishRequest(client, request); + if(retval != UA_STATUSCODE_GOOD) { + UA_PublishRequest_delete(request); + return retval; + } + + UA_UInt32 requestId; + client->currentlyOutStandingPublishRequests++; + + /* Disable the timeout, it is treat in UA_Client_Subscriptions_backgroundPublishInactivityCheck */ + retval = __UA_Client_AsyncServiceEx(client, request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST], + processPublishResponseAsync, + &UA_TYPES[UA_TYPES_PUBLISHRESPONSE], + (void*)request, &requestId, 0); + if(retval != UA_STATUSCODE_GOOD) { + UA_PublishRequest_delete(request); + return retval; + } + } + + return UA_STATUSCODE_GOOD; +} + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/src/client/ua_client_subscriptions_deprecated.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) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016 (c) Sten Grüner + * Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2016-2017 (c) Florian Palm + * Copyright 2017 (c) Frank Meerkötter + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */ + +const UA_SubscriptionSettings UA_SubscriptionSettings_default = { + 500.0, /* .requestedPublishingInterval */ + 10000, /* .requestedLifetimeCount */ + 1, /* .requestedMaxKeepAliveCount */ + 0, /* .maxNotificationsPerPublish */ + true, /* .publishingEnabled */ + 0 /* .priority */ +}; + +UA_StatusCode +UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings, + UA_UInt32 *newSubscriptionId) { + UA_CreateSubscriptionRequest request; + UA_CreateSubscriptionRequest_init(&request); + request.requestedPublishingInterval = settings.requestedPublishingInterval; + request.requestedLifetimeCount = settings.requestedLifetimeCount; + request.requestedMaxKeepAliveCount = settings.requestedMaxKeepAliveCount; + request.maxNotificationsPerPublish = settings.maxNotificationsPerPublish; + request.publishingEnabled = settings.publishingEnabled; + request.priority = settings.priority; + + UA_CreateSubscriptionResponse response = + UA_Client_Subscriptions_create(client, request, NULL, NULL, NULL); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD && newSubscriptionId) + *newSubscriptionId = response.subscriptionId; + + UA_CreateSubscriptionResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) { + UA_DeleteSubscriptionsRequest request; + UA_DeleteSubscriptionsRequest_init(&request); + request.subscriptionIdsSize = 1; + request.subscriptionIds = &subscriptionId; + + UA_DeleteSubscriptionsResponse response = + UA_Client_Subscriptions_delete(client, request); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + if(response.resultsSize != 1) + retval = UA_STATUSCODE_BADINTERNALERROR; + } + + if(retval == UA_STATUSCODE_GOOD) + retval = response.results[0]; + + UA_DeleteSubscriptionsResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) { + if(client->state < UA_CLIENTSTATE_SESSION) + return UA_STATUSCODE_BADSERVERNOTCONNECTED; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + UA_DateTime now = UA_DateTime_nowMonotonic(); + UA_DateTime maxDate = now + (UA_DateTime)(client->config.timeout * UA_DATETIME_MSEC); + + UA_Boolean moreNotifications = true; + while(moreNotifications) { + UA_PublishRequest request; + UA_PublishRequest_init(&request); + retval = UA_Client_preparePublishRequest(client, &request); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Manually increase the number of sent publish requests. Otherwise we + * send out one too many when we process async responses when we wait + * for the correct publish response. The + * currentlyOutStandingPublishRequests will be reduced during processing + * of the response. */ + client->currentlyOutStandingPublishRequests++; + + UA_PublishResponse response; + __UA_Client_Service(client, + &request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST], + &response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + UA_Client_Subscriptions_processPublishResponse(client, &request, &response); + UA_PublishRequest_deleteMembers(&request); + + now = UA_DateTime_nowMonotonic(); + if(now > maxDate) { + moreNotifications = UA_FALSE; + retval = UA_STATUSCODE_GOODNONCRITICALTIMEOUT; + } else { + moreNotifications = response.moreNotifications; + } + + UA_PublishResponse_deleteMembers(&response); + UA_PublishRequest_deleteMembers(&request); + } + + if(client->state < UA_CLIENTSTATE_SESSION) + return UA_STATUSCODE_BADSERVERNOTCONNECTED; + + return retval; +} + +/* Callbacks for the MonitoredItems. The callbacks for the deprecated API are + * wrapped. The wrapper is cleaned up upon destruction. */ + +typedef struct { + UA_MonitoredItemHandlingFunction origCallback; + void *context; +} dataChangeCallbackWrapper; + +static void +dataChangeCallback(UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext, UA_DataValue *value) { + dataChangeCallbackWrapper *wrapper = (dataChangeCallbackWrapper*)monContext; + wrapper->origCallback(client, monId, value, wrapper->context); +} + +typedef struct { + UA_MonitoredEventHandlingFunction origCallback; + void *context; +} eventCallbackWrapper; + +static void +eventCallback(UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext, size_t nEventFields, + UA_Variant *eventFields) { + eventCallbackWrapper *wrapper = (eventCallbackWrapper*)monContext; + wrapper->origCallback(client, monId, nEventFields, eventFields, wrapper->context); +} + +static void +deleteMonitoredItemCallback(UA_Client *client, UA_UInt32 subId, void *subContext, + UA_UInt32 monId, void *monContext) { + UA_free(monContext); +} + +static UA_StatusCode +addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId, + UA_MonitoredItemCreateRequest *items, size_t itemsSize, + UA_MonitoredItemHandlingFunction *hfs, void **hfContexts, + UA_StatusCode *itemResults, UA_UInt32 *newMonitoredItemIds) { + /* Create array of wrappers and callbacks */ + UA_STACKARRAY(dataChangeCallbackWrapper*, wrappers, itemsSize); + UA_STACKARRAY(UA_Client_DeleteMonitoredItemCallback, deleteCbs, itemsSize); + UA_STACKARRAY(UA_Client_DataChangeNotificationCallback, wrapperCbs, itemsSize); + + for(size_t i = 0; i < itemsSize; i++) { + wrappers[i] = (dataChangeCallbackWrapper*)UA_malloc(sizeof(dataChangeCallbackWrapper)); + if(!wrappers[i]) { + for(size_t j = 0; j < i; j++) + UA_free(wrappers[j]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + wrappers[i]->origCallback = (UA_MonitoredItemHandlingFunction)(uintptr_t)hfs[i]; + wrappers[i]->context = hfContexts[i]; + + deleteCbs[i] = deleteMonitoredItemCallback; + wrapperCbs[i] = dataChangeCallback; + } + + /* Prepare the request */ + UA_CreateMonitoredItemsRequest request; + UA_CreateMonitoredItemsRequest_init(&request); + request.subscriptionId = subscriptionId; + request.itemsToCreateSize = itemsSize; + request.itemsToCreate = items; + + /* Process and return */ + UA_CreateMonitoredItemsResponse response = + UA_Client_MonitoredItems_createDataChanges(client, request, (void**)wrappers, + wrapperCbs, deleteCbs); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD && response.resultsSize != itemsSize) + retval = UA_STATUSCODE_BADINTERNALERROR; + + if(retval == UA_STATUSCODE_GOOD) { + for(size_t i = 0; i < itemsSize; i++) { + itemResults[i] = response.results[i].statusCode; + newMonitoredItemIds[i] = response.results[i].monitoredItemId; + } + } + + UA_CreateMonitoredItemsResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_Subscriptions_addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId, + UA_MonitoredItemCreateRequest *items, size_t itemsSize, + UA_MonitoredItemHandlingFunction *hfs, + void **hfContexts, UA_StatusCode *itemResults, + UA_UInt32 *newMonitoredItemIds) { + return addMonitoredItems(client, subscriptionId, items, itemsSize, hfs, hfContexts, itemResults, + newMonitoredItemIds); +} + +UA_StatusCode +UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId, + UA_NodeId nodeId, UA_UInt32 attributeID, + UA_MonitoredItemHandlingFunction hf, void *hfContext, + UA_UInt32 *newMonitoredItemId, UA_Double samplingInterval) { + UA_MonitoredItemCreateRequest item; + UA_MonitoredItemCreateRequest_init(&item); + item.itemToMonitor.nodeId = nodeId; + item.itemToMonitor.attributeId = attributeID; + item.monitoringMode = UA_MONITORINGMODE_REPORTING; + item.requestedParameters.samplingInterval = samplingInterval; + item.requestedParameters.discardOldest = true; + item.requestedParameters.queueSize = 1; + + UA_StatusCode retval_item = UA_STATUSCODE_GOOD; + UA_StatusCode retval = + addMonitoredItems(client, subscriptionId, &item, 1, + (UA_MonitoredItemHandlingFunction*)(uintptr_t)&hf, + &hfContext, &retval_item, newMonitoredItemId); + return retval | retval_item; +} + +static UA_StatusCode +addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId, + UA_MonitoredItemCreateRequest *items, size_t itemsSize, + UA_MonitoredEventHandlingFunction *hfs, + void **hfContexts, UA_StatusCode *itemResults, + UA_UInt32 *newMonitoredItemIds) { + /* Create array of wrappers and callbacks */ + UA_STACKARRAY(eventCallbackWrapper*, wrappers, itemsSize); + UA_STACKARRAY(UA_Client_DeleteMonitoredItemCallback, deleteCbs, itemsSize); + UA_STACKARRAY(UA_Client_EventNotificationCallback, wrapperCbs, itemsSize); + + for(size_t i = 0; i < itemsSize; i++) { + wrappers[i] = (eventCallbackWrapper*)UA_malloc(sizeof(eventCallbackWrapper)); + if(!wrappers[i]) { + for(size_t j = 0; j < i; j++) + UA_free(wrappers[j]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + wrappers[i]->origCallback = (UA_MonitoredEventHandlingFunction)(uintptr_t)hfs[i]; + wrappers[i]->context = hfContexts[i]; + + deleteCbs[i] = deleteMonitoredItemCallback; + wrapperCbs[i] = eventCallback; + } + + /* Prepare the request */ + UA_CreateMonitoredItemsRequest request; + UA_CreateMonitoredItemsRequest_init(&request); + request.subscriptionId = subscriptionId; + request.itemsToCreateSize = itemsSize; + request.itemsToCreate = items; + + /* Process and return */ + UA_CreateMonitoredItemsResponse response = + UA_Client_MonitoredItems_createEvents(client, request, (void**)wrappers, + wrapperCbs, deleteCbs); + + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD && response.resultsSize != itemsSize) + retval = UA_STATUSCODE_BADINTERNALERROR; + + if(retval == UA_STATUSCODE_GOOD) { + for(size_t i = 0; i < itemsSize; i++) + itemResults[i] = response.results[i].statusCode; + } + + UA_CreateMonitoredItemsResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_Subscriptions_addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId, + UA_MonitoredItemCreateRequest *items, size_t itemsSize, + UA_MonitoredEventHandlingFunction *hfs, + void **hfContexts, UA_StatusCode *itemResults, + UA_UInt32 *newMonitoredItemIds) { + return addMonitoredEvents(client, subscriptionId, items, itemsSize, hfs, + hfContexts, itemResults, newMonitoredItemIds); +} + +UA_StatusCode +UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, UA_UInt32 subscriptionId, + const UA_NodeId nodeId, UA_UInt32 attributeID, + const UA_SimpleAttributeOperand *selectClauses, + size_t selectClausesSize, + const UA_ContentFilterElement *whereClauses, + size_t whereClausesSize, + const UA_MonitoredEventHandlingFunction hf, + void *hfContext, UA_UInt32 *newMonitoredItemId) { + UA_MonitoredItemCreateRequest item; + UA_MonitoredItemCreateRequest_init(&item); + item.itemToMonitor.nodeId = nodeId; + item.itemToMonitor.attributeId = attributeID; + item.monitoringMode = UA_MONITORINGMODE_REPORTING; + item.requestedParameters.samplingInterval = 0; + item.requestedParameters.discardOldest = false; + + UA_EventFilter *evFilter = UA_EventFilter_new(); + if(!evFilter) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_EventFilter_init(evFilter); + evFilter->selectClausesSize = selectClausesSize; + evFilter->selectClauses = (UA_SimpleAttributeOperand*)(uintptr_t)selectClauses; + evFilter->whereClause.elementsSize = whereClausesSize; + evFilter->whereClause.elements = (UA_ContentFilterElement*)(uintptr_t)whereClauses; + + item.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; + item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER]; + item.requestedParameters.filter.content.decoded.data = evFilter; + UA_StatusCode retval_item = UA_STATUSCODE_GOOD; + UA_StatusCode retval = addMonitoredEvents(client, subscriptionId, &item, 1, + (UA_MonitoredEventHandlingFunction*)(uintptr_t)&hf, + &hfContext, &retval_item, newMonitoredItemId); + UA_free(evFilter); + return retval | retval_item; +} + +static UA_StatusCode +removeMonitoredItems(UA_Client *client, UA_UInt32 subscriptionId, + UA_UInt32 *monitoredItemIds, size_t itemsSize, + UA_StatusCode *itemResults) { + UA_DeleteMonitoredItemsRequest request; + UA_DeleteMonitoredItemsRequest_init(&request); + request.subscriptionId = subscriptionId; + request.monitoredItemIdsSize = itemsSize; + request.monitoredItemIds = monitoredItemIds; + + UA_DeleteMonitoredItemsResponse response = UA_Client_MonitoredItems_delete(client, request); + UA_StatusCode retval = response.responseHeader.serviceResult; + if(retval == UA_STATUSCODE_GOOD) { + if(response.resultsSize != itemsSize) { + retval = UA_STATUSCODE_BADINTERNALERROR; + } else { + for(size_t i = 0; i < itemsSize; i++) + itemResults[i] = response.results[i]; + } + } + UA_DeleteMonitoredItemsResponse_deleteMembers(&response); + return retval; +} + +UA_StatusCode +UA_Client_Subscriptions_removeMonitoredItems(UA_Client *client, UA_UInt32 subscriptionId, + UA_UInt32 *monitoredItemIds, size_t itemsSize, + UA_StatusCode *itemResults) { + return removeMonitoredItems(client, subscriptionId, monitoredItemIds, itemsSize, itemResults); +} + +UA_StatusCode +UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId, + UA_UInt32 monitoredItemId) { + UA_StatusCode retval_item = UA_STATUSCODE_GOOD; + UA_StatusCode retval = removeMonitoredItems(client, subscriptionId, &monitoredItemId, 1, &retval_item); + return retval | retval_item; +} + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/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 */ + +#include <limits.h> + +/* 2000-03-01 (mod 400 year, immediately after feb29 */ +#define LEAPOCH (946684800LL + 86400*(31+29)) + +#define DAYS_PER_400Y (365*400 + 97) +#define DAYS_PER_100Y (365*100 + 24) +#define DAYS_PER_4Y (365*4 + 1) + +int __secs_to_tm(long long t, struct mytm *tm) { + long long days, secs, years; + int remdays, remsecs, remyears; + int qc_cycles, c_cycles, q_cycles; + int months; + int wday, yday, leap; + static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29}; + + /* Reject time_t values whose year would overflow int */ + if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) + return -1; + + secs = t - LEAPOCH; + days = secs / 86400LL; + remsecs = (int)(secs % 86400); + if (remsecs < 0) { + remsecs += 86400; + --days; + } + + wday = (int)((3+days)%7); + if (wday < 0) wday += 7; + + qc_cycles = (int)(days / DAYS_PER_400Y); + remdays = (int)(days % DAYS_PER_400Y); + if (remdays < 0) { + remdays += DAYS_PER_400Y; + --qc_cycles; + } + + c_cycles = remdays / DAYS_PER_100Y; + if (c_cycles == 4) --c_cycles; + remdays -= c_cycles * DAYS_PER_100Y; + + q_cycles = remdays / DAYS_PER_4Y; + if (q_cycles == 25) --q_cycles; + remdays -= q_cycles * DAYS_PER_4Y; + + remyears = remdays / 365; + if (remyears == 4) --remyears; + remdays -= remyears * 365; + + leap = !remyears && (q_cycles || !c_cycles); + yday = remdays + 31 + 28 + leap; + if (yday >= 365+leap) yday -= 365+leap; + + years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles; + + for (months=0; days_in_month[months] <= remdays; ++months) + remdays -= days_in_month[months]; + + if (years+100 > INT_MAX || years+100 < INT_MIN) + return -1; + + tm->tm_year = (int)(years + 100); + tm->tm_mon = months + 2; + if (tm->tm_mon >= 12) { + tm->tm_mon -=12; + ++tm->tm_year; + } + tm->tm_mday = remdays + 1; + tm->tm_wday = wday; + tm->tm_yday = yday; + + tm->tm_hour = remsecs / 3600; + tm->tm_min = remsecs / 60 % 60; + tm->tm_sec = remsecs % 60; + + return 0; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/deps/pcg_basic.c" ***********************************/ + +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For additional information about the PCG random number generation scheme, + * including its license and other licensing options, visit + * + * http://www.pcg-random.org + */ + + +void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg32_random_r(rng); + rng->state += initial_state; + pcg32_random_r(rng); +} + +uint32_t pcg32_random_r(pcg32_random_t* rng) { + uint64_t oldstate = rng->state; + rng->state = oldstate * 6364136223846793005ULL + rng->inc; + uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u); + uint32_t rot = (uint32_t)(oldstate >> 59u); + return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31)); /* was (xorshifted >> rot) | (xorshifted << ((-rot) & 31)) */ +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/ua_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. + * + * Copyright 2016-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) frax2222 + * Copyright 2017 (c) Jose Cabral + * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + */ + +/* Enable POSIX features */ +#if !defined(_XOPEN_SOURCE) && !defined(_WRS_KERNEL) +# define _XOPEN_SOURCE 600 +#endif +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#endif +/* On older systems we need to define _BSD_SOURCE. + * _DEFAULT_SOURCE is an alias for that. */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif + +/* Disable some security warnings on MSVC */ +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS +#endif + +/* Assume that Windows versions are newer than Windows XP */ +#if defined(__MINGW32__) && (!defined(WINVER) || WINVER < 0x501) +# undef WINVER +# undef _WIN32_WINDOWS +# undef _WIN32_WINNT +# define WINVER 0x0501 +# define _WIN32_WINDOWS 0x0501 +# define _WIN32_WINNT 0x0501 +#endif + + +#include <stdio.h> // snprintf +#include <string.h> // memset + +#if !defined(UA_FREERTOS) +# include <errno.h> +#else +# define AI_PASSIVE 0x01 +# define TRUE 1 +# define FALSE 0 +# define ioctl ioctlsocket +#endif + +#ifdef _WIN32 +# include <winsock2.h> +# include <ws2tcpip.h> +# define CLOSESOCKET(S) closesocket((SOCKET)S) +# define ssize_t int +# define WIN32_INT (int) +# define OPTVAL_TYPE char +# define ERR_CONNECTION_PROGRESS WSAEWOULDBLOCK +# define UA_sleep_ms(X) Sleep(X) +#else /* _WIN32 */ +# if defined(UA_FREERTOS) +# define UA_FREERTOS_HOSTNAME "10.200.4.114" +static inline int gethostname_freertos(char* name, size_t len){ + if(strlen(UA_FREERTOS_HOSTNAME) > (len)) + return -1; + strcpy(name, UA_FREERTOS_HOSTNAME); + return 0; +} +#define gethostname gethostname_freertos +# include <lwip/tcpip.h> +# include <lwip/netdb.h> +# define CLOSESOCKET(S) lwip_close(S) +# define sockaddr_storage sockaddr +# ifdef BYTE_ORDER +# undef BYTE_ORDER +# endif +# define UA_sleep_ms(X) vTaskDelay(pdMS_TO_TICKS(X)) +# else /* Not freeRTOS */ +# define CLOSESOCKET(S) close(S) +# include <arpa/inet.h> +# include <netinet/in.h> +# include <netdb.h> +# include <sys/ioctl.h> +# if defined(_WRS_KERNEL) +# include <hostLib.h> +# include <selectLib.h> +# define UA_sleep_ms(X) \ + { \ + struct timespec timeToSleep; \ + timeToSleep.tv_sec = X / 1000; \ + timeToSleep.tv_nsec = 1000000 * (X % 1000); \ + nanosleep(&timeToSleep, NULL); \ + } +# else /* defined(_WRS_KERNEL) */ +# include <sys/select.h> +# define UA_sleep_ms(X) usleep(X * 1000) +# endif /* defined(_WRS_KERNEL) */ +# endif /* Not freeRTOS */ + +# define SOCKET int +# define WIN32_INT +# define OPTVAL_TYPE int +# define ERR_CONNECTION_PROGRESS EINPROGRESS + + +# include <fcntl.h> +# include <unistd.h> // read, write, close + +# ifdef __QNX__ +# include <sys/socket.h> +# endif +# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# include <sys/param.h> +# if defined(BSD) +# include<sys/socket.h> +# endif +# endif +# if !defined(__CYGWIN__) && !defined(UA_FREERTOS) +# include <netinet/tcp.h> +# endif +#endif /* _WIN32 */ + +/* unsigned int for windows and workaround to a glibc bug */ +/* Additionally if GNU_LIBRARY is not defined, it may be using + * musl libc (e.g. Docker Alpine) */ +#if defined(_WIN32) || defined(__OpenBSD__) || \ + (defined(__GNU_LIBRARY__) && (__GNU_LIBRARY__ <= 6) && \ + (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 16) || \ + !defined(__GNU_LIBRARY__)) +# define UA_fd_set(fd, fds) FD_SET((unsigned int)fd, fds) +# define UA_fd_isset(fd, fds) FD_ISSET((unsigned int)fd, fds) +#else +# define UA_fd_set(fd, fds) FD_SET(fd, fds) +# define UA_fd_isset(fd, fds) FD_ISSET(fd, fds) +#endif + +#ifdef UNDER_CE +# define errno WSAGetLastError() +#endif + +#ifdef _WIN32 +# define errno__ WSAGetLastError() +# define INTERRUPTED WSAEINTR +# define WOULDBLOCK WSAEWOULDBLOCK +# define AGAIN WSAEWOULDBLOCK +#else +# define errno__ errno +# define INTERRUPTED EINTR +# define WOULDBLOCK EWOULDBLOCK +# define AGAIN EAGAIN +#endif + + +/****************************/ +/* Generic Socket Functions */ +/****************************/ + +static UA_StatusCode +connection_getsendbuffer(UA_Connection *connection, + size_t length, UA_ByteString *buf) { + if(length > connection->remoteConf.recvBufferSize) + return UA_STATUSCODE_BADCOMMUNICATIONERROR; + return UA_ByteString_allocBuffer(buf, length); +} + +static void +connection_releasesendbuffer(UA_Connection *connection, + UA_ByteString *buf) { + UA_ByteString_deleteMembers(buf); +} + +static void +connection_releaserecvbuffer(UA_Connection *connection, + UA_ByteString *buf) { + UA_ByteString_deleteMembers(buf); +} + +static UA_StatusCode +connection_write(UA_Connection *connection, UA_ByteString *buf) { + if(connection->state == UA_CONNECTION_CLOSED) { + UA_ByteString_deleteMembers(buf); + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + + /* Prevent OS signals when sending to a closed socket */ + int flags = 0; +#ifdef MSG_NOSIGNAL + flags |= MSG_NOSIGNAL; +#endif + + /* Send the full buffer. This may require several calls to send */ + size_t nWritten = 0; + do { + ssize_t n = 0; + do { + size_t bytes_to_send = buf->length - nWritten; + n = send((SOCKET)connection->sockfd, + (const char*)buf->data + nWritten, + WIN32_INT bytes_to_send, flags); + if(n < 0 && errno__ != INTERRUPTED && errno__ != AGAIN) { + connection->close(connection); + UA_ByteString_deleteMembers(buf); + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + } while(n < 0); + nWritten += (size_t)n; + } while(nWritten < buf->length); + + /* Free the buffer */ + UA_ByteString_deleteMembers(buf); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +connection_recv(UA_Connection *connection, UA_ByteString *response, + UA_UInt32 timeout) { + if(connection->state == UA_CONNECTION_CLOSED) + return UA_STATUSCODE_BADCONNECTIONCLOSED; + + /* Listen on the socket for the given timeout until a message arrives */ + if(timeout > 0) { + fd_set fdset; + FD_ZERO(&fdset); + UA_fd_set(connection->sockfd, &fdset); + UA_UInt32 timeout_usec = timeout * 1000; + struct timeval tmptv = {(long int)(timeout_usec / 1000000), + (long int)(timeout_usec % 1000000)}; + int resultsize = select(connection->sockfd+1, &fdset, NULL, + NULL, &tmptv); + + /* No result */ + if(resultsize == 0) + return UA_STATUSCODE_GOODNONCRITICALTIMEOUT; + + if(resultsize == -1) { + /* The call to select was interrupted manually. Act as if it timed + * out */ + if(errno == EINTR) + return UA_STATUSCODE_GOODNONCRITICALTIMEOUT; + + /* The error cannot be recovered. Close the connection. */ + connection->close(connection); + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + } + + response->data = (UA_Byte*) + UA_malloc(connection->localConf.recvBufferSize); + if(!response->data) { + response->length = 0; + return UA_STATUSCODE_BADOUTOFMEMORY; /* not enough memory retry */ + } + + /* Get the received packet(s) */ + ssize_t ret = recv(connection->sockfd, (char*)response->data, + connection->localConf.recvBufferSize, 0); + + /* The remote side closed the connection */ + if(ret == 0) { + UA_ByteString_deleteMembers(response); + connection->close(connection); + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + + /* Error case */ + if(ret < 0) { + UA_ByteString_deleteMembers(response); + if(errno__ == INTERRUPTED || (timeout > 0) ? + false : (errno__ == EAGAIN || errno__ == WOULDBLOCK)) + return UA_STATUSCODE_GOOD; /* statuscode_good but no data -> retry */ + connection->close(connection); + return UA_STATUSCODE_BADCONNECTIONCLOSED; + } + + /* Set the length of the received buffer */ + response->length = (size_t)ret; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +socket_set_nonblocking(SOCKET sockfd) { +#ifdef _WIN32 + u_long iMode = 1; + if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR) + return UA_STATUSCODE_BADINTERNALERROR; +#elif defined(_WRS_KERNEL) || defined(UA_FREERTOS) + int on = TRUE; + if(ioctl(sockfd, FIONBIO, &on) < 0) + return UA_STATUSCODE_BADINTERNALERROR; +#else + int opts = fcntl(sockfd, F_GETFL); + if(opts < 0 || fcntl(sockfd, F_SETFL, opts|O_NONBLOCK) < 0) + return UA_STATUSCODE_BADINTERNALERROR; +#endif + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +socket_set_blocking(SOCKET sockfd) { +#ifdef _WIN32 + u_long iMode = 0; + if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR) + return UA_STATUSCODE_BADINTERNALERROR; +#elif defined(_WRS_KERNEL) || defined(UA_FREERTOS) + int on = FALSE; + if(ioctl(sockfd, FIONBIO, &on) < 0) + return UA_STATUSCODE_BADINTERNALERROR; +#else + int opts = fcntl(sockfd, F_GETFL); + if(opts < 0 || fcntl(sockfd, F_SETFL, opts & (~O_NONBLOCK)) < 0) + return UA_STATUSCODE_BADINTERNALERROR; +#endif + return UA_STATUSCODE_GOOD; +} + +/***************************/ +/* Server NetworkLayer TCP */ +/***************************/ + +#define MAXBACKLOG 100 +#define NOHELLOTIMEOUT 120000 /* timeout in ms before close the connection + * if server does not receive Hello Message */ + +typedef struct ConnectionEntry { + UA_Connection connection; + LIST_ENTRY(ConnectionEntry) pointers; +} ConnectionEntry; + +typedef struct { + UA_Logger logger; + UA_ConnectionConfig conf; + UA_UInt16 port; + UA_Int32 serverSockets[FD_SETSIZE]; + UA_UInt16 serverSocketsSize; + LIST_HEAD(, ConnectionEntry) connections; +} ServerNetworkLayerTCP; + +static void +ServerNetworkLayerTCP_freeConnection(UA_Connection *connection) { + UA_Connection_deleteMembers(connection); + UA_free(connection); +} + +/* This performs only 'shutdown'. 'close' is called when the shutdown + * socket is returned from select. */ +static void +ServerNetworkLayerTCP_close(UA_Connection *connection) { + if (connection->state == UA_CONNECTION_CLOSED) + return; + shutdown((SOCKET)connection->sockfd, 2); + connection->state = UA_CONNECTION_CLOSED; +} + +static UA_StatusCode +ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd, + struct sockaddr_storage *remote) { + /* Set nonblocking */ + socket_set_nonblocking(newsockfd); + + /* Do not merge packets on the socket (disable Nagle's algorithm) */ + int dummy = 1; + if(setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, + (const char *)&dummy, sizeof(dummy)) < 0) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK, + "Cannot set socket option TCP_NODELAY. Error: %s", + errno_str)); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + +#if !defined(UA_FREERTOS) + /* Get the peer name for logging */ + char remote_name[100]; + int res = getnameinfo((struct sockaddr*)remote, + sizeof(struct sockaddr_storage), + remote_name, sizeof(remote_name), + NULL, 0, NI_NUMERICHOST); + if(res == 0) { + UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | New connection over TCP from %s", + (int)newsockfd, remote_name); + } else { + UA_LOG_SOCKET_ERRNO_WRAP(UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | New connection over TCP, " + "getnameinfo failed with error: %s", + (int)newsockfd, errno_str)); + } +#endif + /* Allocate and initialize the connection */ + ConnectionEntry *e = (ConnectionEntry*)UA_malloc(sizeof(ConnectionEntry)); + if(!e){ + CLOSESOCKET(newsockfd); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + UA_Connection *c = &e->connection; + memset(c, 0, sizeof(UA_Connection)); + c->sockfd = newsockfd; + c->handle = layer; + c->localConf = layer->conf; + c->remoteConf = layer->conf; + c->send = connection_write; + c->close = ServerNetworkLayerTCP_close; + c->free = ServerNetworkLayerTCP_freeConnection; + c->getSendBuffer = connection_getsendbuffer; + c->releaseSendBuffer = connection_releasesendbuffer; + c->releaseRecvBuffer = connection_releaserecvbuffer; + c->state = UA_CONNECTION_OPENING; + c->openingDate = UA_DateTime_nowMonotonic(); + + /* Add to the linked list */ + LIST_INSERT_HEAD(&layer->connections, e, pointers); + return UA_STATUSCODE_GOOD; +} + +static void +addServerSocket(ServerNetworkLayerTCP *layer, struct addrinfo *ai) { + /* Create the server socket */ + SOCKET newsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); +#ifdef _WIN32 + if(newsock == INVALID_SOCKET) +#else + if(newsock < 0) +#endif + { + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Error opening the server socket"); + return; + } + + /* Some Linux distributions have net.ipv6.bindv6only not activated. So + * sockets can double-bind to IPv4 and IPv6. This leads to problems. Use + * AF_INET6 sockets only for IPv6. */ + + int optval = 1; +#if !defined(UA_FREERTOS) + if(ai->ai_family == AF_INET6 && + setsockopt(newsock, IPPROTO_IPV6, IPV6_V6ONLY, + (const char*)&optval, sizeof(optval)) == -1) { + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Could not set an IPv6 socket to IPv6 only"); + CLOSESOCKET(newsock); + return; + } +#endif + if(setsockopt(newsock, SOL_SOCKET, SO_REUSEADDR, + (const char *)&optval, sizeof(optval)) == -1) { + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Could not make the socket reusable"); + CLOSESOCKET(newsock); + return; + } + + + if(socket_set_nonblocking(newsock) != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Could not set the server socket to nonblocking"); + CLOSESOCKET(newsock); + return; + } + + /* Bind socket to address */ + if(bind(newsock, ai->ai_addr, WIN32_INT ai->ai_addrlen) < 0) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Error binding a server socket: %s", errno_str)); + CLOSESOCKET(newsock); + return; + } + + /* Start listening */ + if(listen(newsock, MAXBACKLOG) < 0) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Error listening on server socket: %s", errno_str)); + CLOSESOCKET(newsock); + return; + } + + layer->serverSockets[layer->serverSocketsSize] = (UA_Int32)newsock; + layer->serverSocketsSize++; +} + +static UA_StatusCode +ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, const UA_String *customHostname) { +#ifdef _WIN32 + WORD wVersionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + WSAStartup(wVersionRequested, &wsaData); +#endif + + ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle; + + /* Get the discovery url from the hostname */ + UA_String du = UA_STRING_NULL; + if (customHostname->length) { + char discoveryUrl[256]; +#ifndef _MSC_VER + du.length = (size_t)snprintf(discoveryUrl, 255, "opc.tcp://%.*s:%d/", + (int)customHostname->length, + customHostname->data, + layer->port); +#else + du.length = (size_t)_snprintf_s(discoveryUrl, 255, _TRUNCATE, + "opc.tcp://%.*s:%d/", + (int)customHostname->length, + customHostname->data, + layer->port); +#endif + du.data = (UA_Byte*)discoveryUrl; + }else{ + char hostname[256]; + if(gethostname(hostname, 255) == 0) { + char discoveryUrl[256]; +#ifndef _MSC_VER + du.length = (size_t)snprintf(discoveryUrl, 255, "opc.tcp://%s:%d/", + hostname, layer->port); +#else + du.length = (size_t)_snprintf_s(discoveryUrl, 255, _TRUNCATE, + "opc.tcp://%s:%d/", hostname, + layer->port); +#endif + du.data = (UA_Byte*)discoveryUrl; + } + } + UA_String_copy(&du, &nl->discoveryUrl); + + /* Get addrinfo of the server and create server sockets */ + char portno[6]; +#ifndef _MSC_VER + snprintf(portno, 6, "%d", layer->port); +#else + _snprintf_s(portno, 6, _TRUNCATE, "%d", layer->port); +#endif + struct addrinfo hints, *res; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; +#if defined(UA_FREERTOS) + hints.ai_protocol = IPPROTO_TCP; + char hostname[] = UA_FREERTOS_HOSTNAME; + if(getaddrinfo(hostname, portno, &hints, &res) != 0) +#else + if(getaddrinfo(NULL, portno, &hints, &res) != 0) +#endif + return UA_STATUSCODE_BADINTERNALERROR; + + /* There might be serveral addrinfos (for different network cards, + * IPv4/IPv6). Add a server socket for all of them. */ + struct addrinfo *ai = res; + for(layer->serverSocketsSize = 0; + layer->serverSocketsSize < FD_SETSIZE && ai != NULL; + ai = ai->ai_next) + addServerSocket(layer, ai); + freeaddrinfo(res); + + UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, + "TCP network layer listening on %.*s", + (int)nl->discoveryUrl.length, nl->discoveryUrl.data); + return UA_STATUSCODE_GOOD; +} + +/* After every select, reset the sockets to listen on */ +static UA_Int32 +setFDSet(ServerNetworkLayerTCP *layer, fd_set *fdset) { + FD_ZERO(fdset); + UA_Int32 highestfd = 0; + for(UA_UInt16 i = 0; i < layer->serverSocketsSize; i++) { + UA_fd_set(layer->serverSockets[i], fdset); + if(layer->serverSockets[i] > highestfd) + highestfd = layer->serverSockets[i]; + } + + ConnectionEntry *e; + LIST_FOREACH(e, &layer->connections, pointers) { + UA_fd_set(e->connection.sockfd, fdset); + if(e->connection.sockfd > highestfd) + highestfd = e->connection.sockfd; + } + + return highestfd; +} + +static UA_StatusCode +ServerNetworkLayerTCP_listen(UA_ServerNetworkLayer *nl, UA_Server *server, + UA_UInt16 timeout) { + /* Every open socket can generate two jobs */ + ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle; + + if (layer->serverSocketsSize == 0) + return UA_STATUSCODE_GOOD; + + /* Listen on open sockets (including the server) */ + fd_set fdset, errset; + UA_Int32 highestfd = setFDSet(layer, &fdset); + setFDSet(layer, &errset); + struct timeval tmptv = {0, timeout * 1000}; + if (select(highestfd+1, &fdset, NULL, &errset, &tmptv) < 0) { + UA_LOG_SOCKET_ERRNO_WRAP( + UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, + "Socket select failed with %s", errno_str)); + // we will retry, so do not return bad + return UA_STATUSCODE_GOOD; + } + + /* Accept new connections via the server sockets */ + for(UA_UInt16 i = 0; i < layer->serverSocketsSize; i++) { + if(!UA_fd_isset(layer->serverSockets[i], &fdset)) + continue; + + struct sockaddr_storage remote; + socklen_t remote_size = sizeof(remote); + SOCKET newsockfd = accept((SOCKET)layer->serverSockets[i], + (struct sockaddr*)&remote, &remote_size); +#ifdef _WIN32 + if(newsockfd == INVALID_SOCKET) +#else + if(newsockfd < 0) +#endif + continue; + + UA_LOG_TRACE(layer->logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | New TCP connection on server socket %i", + (int)newsockfd, layer->serverSockets[i]); + + ServerNetworkLayerTCP_add(layer, (UA_Int32)newsockfd, &remote); + } + + /* Read from established sockets */ + ConnectionEntry *e, *e_tmp; + UA_DateTime now = UA_DateTime_nowMonotonic(); + LIST_FOREACH_SAFE(e, &layer->connections, pointers, e_tmp) { + if ((e->connection.state == UA_CONNECTION_OPENING) && + (now > (e->connection.openingDate + (NOHELLOTIMEOUT * UA_DATETIME_MSEC)))){ + UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Closed by the server (no Hello Message)", + e->connection.sockfd); + LIST_REMOVE(e, pointers); + CLOSESOCKET(e->connection.sockfd); + UA_Server_removeConnection(server, &e->connection); + continue; + } + + if(!UA_fd_isset(e->connection.sockfd, &errset) && + !UA_fd_isset(e->connection.sockfd, &fdset)) + continue; + + UA_LOG_TRACE(layer->logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Activity on the socket", + e->connection.sockfd); + + UA_ByteString buf = UA_BYTESTRING_NULL; + UA_StatusCode retval = connection_recv(&e->connection, &buf, 0); + + if(retval == UA_STATUSCODE_GOOD) { + /* Process packets */ + UA_Server_processBinaryMessage(server, &e->connection, &buf); + connection_releaserecvbuffer(&e->connection, &buf); + } else if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED) { + /* The socket is shutdown but not closed */ + UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Closed", + e->connection.sockfd); + LIST_REMOVE(e, pointers); + CLOSESOCKET(e->connection.sockfd); + UA_Server_removeConnection(server, &e->connection); + } + } + return UA_STATUSCODE_GOOD; +} + +static void +ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Server *server) { + ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle; + UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, + "Shutting down the TCP network layer"); + + /* Close the server sockets */ + for(UA_UInt16 i = 0; i < layer->serverSocketsSize; i++) { + shutdown((SOCKET)layer->serverSockets[i], 2); + CLOSESOCKET(layer->serverSockets[i]); + } + layer->serverSocketsSize = 0; + + /* Close open connections */ + ConnectionEntry *e; + LIST_FOREACH(e, &layer->connections, pointers) + ServerNetworkLayerTCP_close(&e->connection); + + /* Run recv on client sockets. This picks up the closed sockets and frees + * the connection. */ + ServerNetworkLayerTCP_listen(nl, server, 0); + +#ifdef _WIN32 + WSACleanup(); +#endif +} + +/* run only when the server is stopped */ +static void +ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) { + ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle; + UA_String_deleteMembers(&nl->discoveryUrl); + + /* Hard-close and remove remaining connections. The server is no longer + * running. So this is safe. */ + ConnectionEntry *e, *e_tmp; + LIST_FOREACH_SAFE(e, &layer->connections, pointers, e_tmp) { + LIST_REMOVE(e, pointers); + CLOSESOCKET(e->connection.sockfd); + UA_free(e); + } + + /* Free the layer */ + UA_free(layer); +} + +UA_ServerNetworkLayer +UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt16 port, UA_Logger logger) { + UA_ServerNetworkLayer nl; + memset(&nl, 0, sizeof(UA_ServerNetworkLayer)); + nl.start = ServerNetworkLayerTCP_start; + nl.listen = ServerNetworkLayerTCP_listen; + nl.stop = ServerNetworkLayerTCP_stop; + nl.deleteMembers = ServerNetworkLayerTCP_deleteMembers; + + ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*) + UA_calloc(1,sizeof(ServerNetworkLayerTCP)); + if(!layer) + return nl; + nl.handle = layer; + + layer->logger = (logger != NULL ? logger : UA_Log_Stdout); + layer->conf = conf; + layer->port = port; + + return nl; +} + +/***************************/ +/* Client NetworkLayer TCP */ +/***************************/ + +static void +ClientNetworkLayerTCP_close(UA_Connection *connection) { + if (connection->state == UA_CONNECTION_CLOSED) + return; + shutdown((SOCKET)connection->sockfd, 2); + CLOSESOCKET(connection->sockfd); + connection->state = UA_CONNECTION_CLOSED; +} + +UA_Connection +UA_ClientConnectionTCP(UA_ConnectionConfig conf, + const char *endpointUrl, const UA_UInt32 timeout, + UA_Logger logger) { +#ifdef _WIN32 + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2, 2); + WSAStartup(wVersionRequested, &wsaData); +#endif + + if(logger == NULL) { + logger = UA_Log_Stdout; + } + + UA_Connection connection; + memset(&connection, 0, sizeof(UA_Connection)); + connection.state = UA_CONNECTION_CLOSED; + connection.localConf = conf; + connection.remoteConf = conf; + connection.send = connection_write; + connection.recv = connection_recv; + connection.close = ClientNetworkLayerTCP_close; + connection.free = NULL; + connection.getSendBuffer = connection_getsendbuffer; + connection.releaseSendBuffer = connection_releasesendbuffer; + connection.releaseRecvBuffer = connection_releaserecvbuffer; + + UA_String endpointUrlString = UA_STRING((char*)(uintptr_t)endpointUrl); + 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(&endpointUrlString, &hostnameString, + &port, &pathString); + if(parse_retval != UA_STATUSCODE_GOOD || hostnameString.length > 511) { + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Server url is invalid: %s", endpointUrl); + 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 %d", port); + } + + struct addrinfo hints, *server; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +#if defined(UA_FREERTOS) + hints.ai_protocol = IPPROTO_TCP; +#endif + char portStr[6]; +#ifndef _MSC_VER + snprintf(portStr, 6, "%d", port); +#else + _snprintf_s(portStr, 6, _TRUNCATE, "%d", port); +#endif + int error = getaddrinfo(hostname, portStr, &hints, &server); + if(error != 0 || !server) { +#if !defined(UA_FREERTOS) + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + + "DNS lookup of %s failed with error %s", + hostname, gai_strerror(error)); +#else + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "DNS lookup of %s failed with error", + hostname); +#endif + return connection; + } + + UA_Boolean connected = UA_FALSE; + UA_DateTime dtTimeout = timeout * UA_DATETIME_MSEC; + UA_DateTime connStart = UA_DateTime_nowMonotonic(); + 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 = socket(server->ai_family, + server->ai_socktype, + server->ai_protocol); + #ifdef _WIN32 + if(clientsockfd == INVALID_SOCKET) { + #else + if(clientsockfd < 0) { + #endif + UA_LOG_SOCKET_ERRNO_WRAP(UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Could not create client socket: %s", errno_str)); + freeaddrinfo(server); + return connection; + } + + connection.state = UA_CONNECTION_OPENING; + + /* Connect to the server */ + connection.sockfd = (UA_Int32) clientsockfd; /* cast for win32 */ + + /* Non blocking connect to be able to timeout */ + if (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); + freeaddrinfo(server); + return connection; + } + + /* Non blocking connect */ + error = connect(clientsockfd, server->ai_addr, WIN32_INT server->ai_addrlen); + + if ((error == -1) && (errno__ != 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", + endpointUrl, errno_str)); + freeaddrinfo(server); + return connection; + } + + /* Use select to wait and check if connected */ + if (error == -1 && (errno__ == ERR_CONNECTION_PROGRESS)) { + /* connection in progress. Wait until connected using select */ + UA_DateTime timeSinceStart = UA_DateTime_nowMonotonic() - connStart; + if(timeSinceStart > dtTimeout) + break; + + 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), + (long int) (timeout_usec % 1000000)}; + + int resultsize = select((UA_Int32)(clientsockfd + 1), NULL, &fdset, NULL, &tmptv); + + 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 = 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", + endpointUrl, strerror(ret == 0 ? so_error : errno__)); + 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); + + freeaddrinfo(server); + + if(!connected) { + /* connection timeout */ + if (connection.state != UA_CONNECTION_CLOSED) + ClientNetworkLayerTCP_close(&connection); + UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK, + "Trying to connect to %s timed out", + endpointUrl); + return connection; + } + + + /* We are connected. Reset socket to blocking */ + if(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 = 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; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/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. + * + * Copyright 2016-2017 (c) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + */ + +/* Enable POSIX features */ +#if !defined(_XOPEN_SOURCE) && !defined(_WRS_KERNEL) +# define _XOPEN_SOURCE 600 +#endif +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#endif +/* On older systems we need to define _BSD_SOURCE. + * _DEFAULT_SOURCE is an alias for that. */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif + +#include <time.h> +#ifdef _WIN32 +/* Backup definition of SLIST_ENTRY on mingw winnt.h */ +# ifdef SLIST_ENTRY +# pragma push_macro("SLIST_ENTRY") +# undef SLIST_ENTRY +# define POP_SLIST_ENTRY +# endif +# include <windows.h> +/* restore definition */ +# ifdef POP_SLIST_ENTRY +# undef SLIST_ENTRY +# undef POP_SLIST_ENTRY +# pragma pop_macro("SLIST_ENTRY") +# endif +#else +# include <sys/time.h> +#endif + +#if defined(__APPLE__) || defined(__MACH__) +# include <mach/clock.h> +# include <mach/mach.h> +#endif + + +#if defined(UA_FREERTOS) +#include <task.h> +#endif + +UA_DateTime UA_DateTime_now(void) { +#if defined(_WIN32) + /* Windows filetime has the same definition as UA_DateTime */ + FILETIME ft; + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + ULARGE_INTEGER ul; + ul.LowPart = ft.dwLowDateTime; + ul.HighPart = ft.dwHighDateTime; + return (UA_DateTime)ul.QuadPart; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * UA_DATETIME_SEC) + (tv.tv_usec * UA_DATETIME_USEC) + UA_DATETIME_UNIX_EPOCH; +#endif +} + +/* Credit to https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c */ +UA_Int64 UA_DateTime_localTimeUtcOffset(void) { + time_t gmt, rawtime = time(NULL); + +#ifdef _WIN32 + struct tm ptm; + gmtime_s(&ptm, &rawtime); + // Request that mktime() looksup dst in timezone database + ptm.tm_isdst = -1; + gmt = mktime(&ptm); +#else + struct tm *ptm; + struct tm gbuf; + ptm = gmtime_r(&rawtime, &gbuf); + // Request that mktime() looksup dst in timezone database + ptm->tm_isdst = -1; + gmt = mktime(ptm); +#endif + + return (UA_Int64) (difftime(rawtime, gmt) * UA_DATETIME_SEC); +} + +UA_DateTime UA_DateTime_nowMonotonic(void) { +#if defined(_WIN32) + LARGE_INTEGER freq, ticks; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&ticks); + UA_Double ticks2dt = UA_DATETIME_SEC / (UA_Double)freq.QuadPart; + return (UA_DateTime)(ticks.QuadPart * ticks2dt); +#elif defined(__APPLE__) || defined(__MACH__) + /* OS X does not have clock_gettime, use clock_get_time */ + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + return (mts.tv_sec * UA_DATETIME_SEC) + (mts.tv_nsec / 100); +#elif !defined(CLOCK_MONOTONIC_RAW) +# if defined(UA_FREERTOS) + portTickType TaskTime = xTaskGetTickCount(); + UA_DateTimeStruct UATime; + UATime.milliSec = (UA_UInt16) TaskTime; + struct timespec ts; + ts.tv_sec = UATime.milliSec/1000; + ts.tv_nsec = (UATime.milliSec % 1000)* 1000000; + return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100); +# else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100); +# endif +#else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100); +#endif +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/ua_log_stdout.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) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA + */ + +#include <stdio.h> + +/* ANSI escape sequences for color output taken from here: + * https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c*/ + +#ifdef _WIN32 +# 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 "" +#else +# 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" +#endif + +#ifdef UA_ENABLE_MULTITHREADING +#include <pthread.h> +static pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +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"}; + +#ifdef __clang__ +__attribute__((__format__(__printf__, 3 , 0))) +#endif +void +UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category, + const char *msg, va_list args) { + UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset(); + UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset); + +#ifdef UA_ENABLE_MULTITHREADING + pthread_mutex_lock(&printf_mutex); +#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); + +#ifdef UA_ENABLE_MULTITHREADING + pthread_mutex_unlock(&printf_mutex); +#endif +} + +/*********************************** amalgamated original file "/home/jvoe/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) Julius Pfrommer, Fraunhofer IOSB + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +/* Example access control management. Anonymous and username / password login. + * The access rights are maximally permissive. */ + +typedef struct { + UA_Boolean allowAnonymous; + size_t usernamePasswordLoginSize; + UA_UsernamePasswordLogin *usernamePasswordLogin; +} AccessControlContext; + +#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); + +/************************/ +/* Access Control Logic */ +/************************/ + +static UA_StatusCode +activateSession_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, + const UA_ExtensionObject *userIdentityToken, + void **sessionContext) { + AccessControlContext *context = (AccessControlContext*)ac->context; + + /* The empty token is interpreted as anonymous */ + if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) { + if(!context->allowAnonymous) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + /* No userdata atm */ + *sessionContext = NULL; + return UA_STATUSCODE_GOOD; + } + + /* Could the token be decoded? */ + if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + /* Anonymous login */ + if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) { + if(!context->allowAnonymous) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + const UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*) + userIdentityToken->content.decoded.data; + + /* 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; + + /* No userdata atm */ + *sessionContext = NULL; + return UA_STATUSCODE_GOOD; + } + + /* 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; + + /* TODO: Support encrypted username/password over unencrypted SecureChannels */ + if(userToken->encryptionAlgorithm.length > 0) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + /* Empty username and password */ + if(userToken->userName.length == 0 && userToken->password.length == 0) + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + + /* 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; + + /* No userdata atm */ + *sessionContext = NULL; + return UA_STATUSCODE_GOOD; + } + + /* Unsupported token type */ + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; +} + +static void +closeSession_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext) { + /* no context to clean up */ +} + +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_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_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_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_Boolean +allowAddNode_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddNodesItem *item) { + return true; +} + +static UA_Boolean +allowAddReference_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_AddReferencesItem *item) { + return true; +} + +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_Boolean +allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac, + const UA_NodeId *sessionId, void *sessionContext, + const UA_DeleteReferencesItem *item) { + return true; +} + +/***************************************/ +/* Create Delete Access Control Plugin */ +/***************************************/ + +static void deleteMembers_default(UA_AccessControl *ac) { + UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies, + ac->userTokenPoliciesSize, + &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + + AccessControlContext *context = (AccessControlContext*)ac->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); +} + +UA_AccessControl +UA_AccessControl_default(UA_Boolean allowAnonymous, size_t usernamePasswordLoginSize, + const UA_UsernamePasswordLogin *usernamePasswordLogin) { + AccessControlContext *context = (AccessControlContext*) + UA_malloc(sizeof(AccessControlContext)); + + UA_AccessControl ac; + memset(&ac, 0, sizeof(ac)); + ac.context = context; + ac.deleteMembers = deleteMembers_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.allowDeleteNode = allowDeleteNode_default; + ac.allowDeleteReference = allowDeleteReference_default; + + /* 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) + return ac; + 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 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 ac; + ac.userTokenPoliciesSize = policies; + + policies = 0; + if(allowAnonymous) { + ac.userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS; + ac.userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY); + policies++; + } + + if(usernamePasswordLoginSize > 0) { + ac.userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME; + ac.userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY); + /* No encryption of username/password supported at the moment */ + ac.userTokenPolicies[policies].securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None"); + } + return ac; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/ua_pki_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. + * + * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#ifdef UA_ENABLE_ENCRYPTION +#include <mbedtls/x509.h> +#include <mbedtls/x509_crt.h> +#endif + +/************/ +/* AllowAll */ +/************/ + +static UA_StatusCode +verifyCertificateAllowAll(void *verificationContext, + const UA_ByteString *certificate) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +verifyApplicationURIAllowAll(void *verificationContext, + const UA_ByteString *certificate, + const UA_String *applicationURI) { + return UA_STATUSCODE_GOOD; +} + +static void +deleteVerifyAllowAll(UA_CertificateVerification *cv) { + +} + +void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) { + cv->verifyCertificate = verifyCertificateAllowAll; + cv->verifyApplicationURI = verifyApplicationURIAllowAll; + cv->deleteMembers = deleteVerifyAllowAll; +} + +#ifdef UA_ENABLE_ENCRYPTION + +typedef struct { + mbedtls_x509_crt certificateTrustList; + mbedtls_x509_crl certificateRevocationList; +} CertInfo; + +static UA_StatusCode +certificateVerification_verify(void *verificationContext, + const UA_ByteString *certificate) { + CertInfo *ci = (CertInfo*)verificationContext; + if(!ci) + 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) { + /* 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; + } + + /* 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 + + uint32_t flags = 0; + mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate, + &ci->certificateTrustList, + &ci->certificateRevocationList, + &crtProfile, NULL, &flags, NULL, NULL); + + // TODO: Extend verification + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(mbedErr) { + /* char buff[100]; */ + /* mbedtls_x509_crt_verify_info(buff, 100, "", flags); */ + /* UA_LOG_ERROR(channelContextData->policyContext->securityPolicy->logger, */ + /* UA_LOGCATEGORY_SECURITYPOLICY, */ + /* "Verifying the certificate failed with error: %s", buff); */ + + if(flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) { + retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; + } else if (flags & MBEDTLS_X509_BADCERT_FUTURE || + flags & MBEDTLS_X509_BADCERT_EXPIRED) { + retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID; + } else if(flags & MBEDTLS_X509_BADCERT_REVOKED || + flags & MBEDTLS_X509_BADCRL_EXPIRED) { + retval = UA_STATUSCODE_BADCERTIFICATEREVOKED; + } else { + retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + } + + mbedtls_x509_crt_free(&remoteCertificate); + return retval; +} + +/* 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*/ + /* handle special case */ + if(l == 0) + return (NULL); + + for(; *s != ch; ++s, --l) + if(l == 0) + return (NULL); + return s; +} + +static const unsigned char * +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; +} + +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; + + /* 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; + + /* 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(bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len, + applicationURI->data, applicationURI->length) == NULL) + retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID; + + mbedtls_x509_crt_free(&remoteCertificate); + return retval; +} + +static void +certificateVerification_deleteMembers(UA_CertificateVerification *cv) { + CertInfo *ci = (CertInfo*)cv->context; + if(!ci) + return; + mbedtls_x509_crt_free(&ci->certificateTrustList); + mbedtls_x509_crl_free(&ci->certificateRevocationList); + UA_free(ci); + cv->context = NULL; +} + +UA_StatusCode +UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv, + const UA_ByteString *certificateTrustList, + size_t certificateTrustListSize, + const UA_ByteString *certificateRevocationList, + size_t certificateRevocationListSize) { + CertInfo *ci = (CertInfo*)malloc(sizeof(CertInfo)); + if(!ci) + return UA_STATUSCODE_BADOUTOFMEMORY; + mbedtls_x509_crt_init(&ci->certificateTrustList); + mbedtls_x509_crl_init(&ci->certificateRevocationList); + + cv->context = (void*)ci; + if(certificateTrustListSize > 0) + cv->verifyCertificate = certificateVerification_verify; + else + cv->verifyCertificate = verifyCertificateAllowAll; + cv->deleteMembers = certificateVerification_deleteMembers; + cv->verifyApplicationURI = certificateVerification_verifyApplicationURI; + + int err = 0; + for(size_t i = 0; i < certificateTrustListSize; i++) { + err |= mbedtls_x509_crt_parse(&ci->certificateTrustList, + certificateTrustList[i].data, + certificateTrustList[i].length); + } + for(size_t i = 0; i < certificateRevocationListSize; i++) { + err |= mbedtls_x509_crl_parse(&ci->certificateRevocationList, + certificateRevocationList[i].data, + certificateRevocationList[i].length); + } + + if(err) { + certificateVerification_deleteMembers(cv); + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} + +#endif + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/ua_nodestore_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) Julian Grothoff + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +/* container_of */ +#define container_of(ptr, type, member) \ + (type *)((uintptr_t)ptr - offsetof(type,member)) + +#ifdef UA_ENABLE_MULTITHREADING +#include <pthread.h> +#define BEGIN_CRITSECT(NODEMAP) pthread_mutex_lock(&(NODEMAP)->mutex) +#define END_CRITSECT(NODEMAP) pthread_mutex_unlock(&(NODEMAP)->mutex) +#else +#define BEGIN_CRITSECT(NODEMAP) +#define END_CRITSECT(NODEMAP) +#endif + +/* 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 **entries; + UA_UInt32 size; + UA_UInt32 count; + UA_UInt32 sizePrimeIndex; +#ifdef UA_ENABLE_MULTITHREADING + pthread_mutex_t mutex; /* Protect access */ +#endif +} 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 low; +} + +/* returns an empty slot or null if the nodeid exists or if no empty slot is found. */ +static UA_NodeMapEntry ** +findFreeSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) { + UA_NodeMapEntry **retval = NULL; + UA_UInt32 h = UA_NodeId_hash(nodeid); + UA_UInt32 size = ns->size; + UA_UInt64 idx = mod(h, size); // use 64 bit container to avoid overflow + UA_UInt32 startIdx = (UA_UInt32)idx; + UA_UInt32 hash2 = mod2(h, size); + UA_NodeMapEntry *entry = NULL; + + do { + entry = ns->entries[(UA_UInt32)idx]; + if(entry > UA_NODEMAP_TOMBSTONE && + UA_NodeId_equal(&entry->node.nodeId, nodeid)) + return NULL; + if(!retval && entry <= UA_NODEMAP_TOMBSTONE) + retval = &ns->entries[(UA_UInt32)idx]; + idx += hash2; + if(idx >= size) + idx -= size; + } while((UA_UInt32)idx != startIdx && entry); + + /* NULL is returned if there is no free slot (idx == startIdx). + * Otherwise the first free slot is returned after we are sure, + * that the node id cannot be found in the used hashmap (!entry). */ + return retval; +} + +/* 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; + + UA_NodeMapEntry **oentries = ns->entries; + UA_UInt32 nindex = higher_prime_index(count * 2); + UA_UInt32 nsize = primes[nindex]; + UA_NodeMapEntry **nentries = (UA_NodeMapEntry **)UA_calloc(nsize, sizeof(UA_NodeMapEntry*)); + if(!nentries) + return UA_STATUSCODE_BADOUTOFMEMORY; + + ns->entries = nentries; + 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(oentries[i] <= UA_NODEMAP_TOMBSTONE) + continue; + UA_NodeMapEntry **e = findFreeSlot(ns, &oentries[i]->node.nodeId); + UA_assert(e); + *e = oentries[i]; + ++j; + } + + UA_free(oentries); + return UA_STATUSCODE_GOOD; +} + +static UA_NodeMapEntry * +newEntry(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.nodeClass = nodeClass; + return entry; +} + +static void +deleteEntry(UA_NodeMapEntry *entry) { + UA_Node_deleteMembers(&entry->node); + UA_free(entry); +} + +static void +cleanupEntry(UA_NodeMapEntry *entry) { + if(entry->deleted && entry->refCount == 0) + deleteEntry(entry); +} + +static UA_StatusCode +clearSlot(UA_NodeMap *ns, UA_NodeMapEntry **slot) { + (*slot)->deleted = true; + cleanupEntry(*slot); + *slot = UA_NODEMAP_TOMBSTONE; + --ns->count; + /* Downsize the hashmap if it is very empty */ + if(ns->count * 8 < ns->size && ns->size > 32) + expand(ns); /* Can fail. Just continue with the bigger hashmap. */ + return UA_STATUSCODE_GOOD; +} + +static UA_NodeMapEntry ** +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 64 bit container to avoid overflow + UA_UInt32 hash2 = mod2(h, size); + UA_UInt32 startIdx = (UA_UInt32)idx; + UA_NodeMapEntry *entry = NULL; + + do { + entry = ns->entries[(UA_UInt32)idx]; + if(entry > UA_NODEMAP_TOMBSTONE && + UA_NodeId_equal(&entry->node.nodeId, nodeid)) + return &ns->entries[(UA_UInt32)idx]; + idx += hash2; + if(idx >= size) + idx -= size; + } while((UA_UInt32)idx != startIdx && entry); + + /* NULL is returned if there is no free slot (idx == startIdx) + * and the node id is not found or if the end of the used slots (!entry) + * is reached. */ + return NULL; +} + +/***********************/ +/* Interface functions */ +/***********************/ + +static UA_Node * +UA_NodeMap_newNode(void *context, UA_NodeClass nodeClass) { + UA_NodeMapEntry *entry = newEntry(nodeClass); + if(!entry) + return NULL; + return &entry->node; +} + +static void +UA_NodeMap_deleteNode(void *context, UA_Node *node) { +#ifdef UA_ENABLE_MULTITHREADING + UA_NodeMap *ns = (UA_NodeMap*)context; +#endif + BEGIN_CRITSECT(ns); + UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node); + UA_assert(&entry->node == node); + deleteEntry(entry); + END_CRITSECT(ns); +} + +static const UA_Node * +UA_NodeMap_getNode(void *context, const UA_NodeId *nodeid) { + UA_NodeMap *ns = (UA_NodeMap*)context; + BEGIN_CRITSECT(ns); + UA_NodeMapEntry **entry = findOccupiedSlot(ns, nodeid); + if(!entry) { + END_CRITSECT(ns); + return NULL; + } + ++(*entry)->refCount; + END_CRITSECT(ns); + return (const UA_Node*)&(*entry)->node; +} + +static void +UA_NodeMap_releaseNode(void *context, const UA_Node *node) { + if (!node) + return; +#ifdef UA_ENABLE_MULTITHREADING + UA_NodeMap *ns = (UA_NodeMap*)context; +#endif + BEGIN_CRITSECT(ns); + UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node); + UA_assert(&entry->node == node); + UA_assert(entry->refCount > 0); + --entry->refCount; + cleanupEntry(entry); + END_CRITSECT(ns); +} + +static UA_StatusCode +UA_NodeMap_getNodeCopy(void *context, const UA_NodeId *nodeid, + UA_Node **outNode) { + UA_NodeMap *ns = (UA_NodeMap*)context; + BEGIN_CRITSECT(ns); + UA_NodeMapEntry **slot = findOccupiedSlot(ns, nodeid); + if(!slot) { + END_CRITSECT(ns); + return UA_STATUSCODE_BADNODEIDUNKNOWN; + } + UA_NodeMapEntry *entry = *slot; + UA_NodeMapEntry *newItem = newEntry(entry->node.nodeClass); + if(!newItem) { + END_CRITSECT(ns); + 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 { + deleteEntry(newItem); + } + END_CRITSECT(ns); + return retval; +} + +static UA_StatusCode +UA_NodeMap_removeNode(void *context, const UA_NodeId *nodeid) { + UA_NodeMap *ns = (UA_NodeMap*)context; + BEGIN_CRITSECT(ns); + UA_NodeMapEntry **slot = findOccupiedSlot(ns, nodeid); + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(slot) + retval = clearSlot(ns, slot); + else + retval = UA_STATUSCODE_BADNODEIDUNKNOWN; + END_CRITSECT(ns); + return retval; +} + +static UA_StatusCode +UA_NodeMap_insertNode(void *context, UA_Node *node, + UA_NodeId *addedNodeId) { + UA_NodeMap *ns = (UA_NodeMap*)context; + BEGIN_CRITSECT(ns); + if(ns->size * 3 <= ns->count * 4) { + if(expand(ns) != UA_STATUSCODE_GOOD) { + END_CRITSECT(ns); + return UA_STATUSCODE_BADINTERNALERROR; + } + } + + UA_NodeMapEntry **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, size); // start value, use 64 bit container 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 + + 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); + + if (!slot) { + END_CRITSECT(ns); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + } else { + slot = findFreeSlot(ns, &node->nodeId); + if(!slot) { + deleteEntry(container_of(node, UA_NodeMapEntry, node)); + END_CRITSECT(ns); + return UA_STATUSCODE_BADNODEIDEXISTS; + } + } + + *slot = container_of(node, UA_NodeMapEntry, node); + ++ns->count; + UA_assert(&(*slot)->node == node); + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(addedNodeId) { + retval = UA_NodeId_copy(&node->nodeId, addedNodeId); + if(retval != UA_STATUSCODE_GOOD) + clearSlot(ns, slot); + } + + END_CRITSECT(ns); + return retval; +} + +static UA_StatusCode +UA_NodeMap_replaceNode(void *context, UA_Node *node) { + UA_NodeMap *ns = (UA_NodeMap*)context; + BEGIN_CRITSECT(ns); + UA_NodeMapEntry **slot = findOccupiedSlot(ns, &node->nodeId); + if(!slot) { + END_CRITSECT(ns); + return UA_STATUSCODE_BADNODEIDUNKNOWN; + } + UA_NodeMapEntry *newEntryContainer = container_of(node, UA_NodeMapEntry, node); + if(*slot != newEntryContainer->orig) { + /* The node was updated since the copy was made */ + deleteEntry(newEntryContainer); + END_CRITSECT(ns); + return UA_STATUSCODE_BADINTERNALERROR; + } + (*slot)->deleted = true; + cleanupEntry(*slot); + *slot = newEntryContainer; + END_CRITSECT(ns); + return UA_STATUSCODE_GOOD; +} + +static void +UA_NodeMap_iterate(void *context, void *visitorContext, + UA_NodestoreVisitor visitor) { + UA_NodeMap *ns = (UA_NodeMap*)context; + BEGIN_CRITSECT(ns); + for(UA_UInt32 i = 0; i < ns->size; ++i) { + if(ns->entries[i] > UA_NODEMAP_TOMBSTONE) { + END_CRITSECT(ns); + UA_NodeMapEntry *entry = ns->entries[i]; + entry->refCount++; + visitor(visitorContext, &entry->node); + entry->refCount--; + cleanupEntry(entry); + BEGIN_CRITSECT(ns); + } + } + END_CRITSECT(ns); +} + +static void +UA_NodeMap_delete(void *context) { + UA_NodeMap *ns = (UA_NodeMap*)context; +#ifdef UA_ENABLE_MULTITHREADING + pthread_mutex_destroy(&ns->mutex); +#endif + UA_UInt32 size = ns->size; + UA_NodeMapEntry **entries = ns->entries; + for(UA_UInt32 i = 0; i < size; ++i) { + if(entries[i] > UA_NODEMAP_TOMBSTONE) { + /* On debugging builds, check that all nodes were release */ + UA_assert(entries[i]->refCount == 0); + /* Delete the node */ + deleteEntry(entries[i]); + } + } + UA_free(ns->entries); + UA_free(ns); +} + +UA_StatusCode +UA_Nodestore_default_new(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->entries = (UA_NodeMapEntry**) + UA_calloc(nodemap->size, sizeof(UA_NodeMapEntry*)); + if(!nodemap->entries) { + UA_free(nodemap); + return UA_STATUSCODE_BADOUTOFMEMORY; + } +#ifdef UA_ENABLE_MULTITHREADING + pthread_mutex_init(&nodemap->mutex, NULL); +#endif + + /* Populate the nodestore */ + ns->context = nodemap; + ns->deleteNodestore = UA_NodeMap_delete; + ns->inPlaceEditAllowed = true; + 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; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/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) Julius Pfrommer, Fraunhofer IOSB + * 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 + */ + + +#ifdef UA_ENABLE_ENCRYPTION +#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 UA_INLINE UA_DurationRange +UA_DURATIONRANGE(UA_Duration min, UA_Duration max) { + UA_DurationRange range = {min, max}; + return range; +} + +/*******************************/ +/* Default Connection Settings */ +/*******************************/ + +const UA_ConnectionConfig UA_ConnectionConfig_default = { + 0, /* .protocolVersion */ + 65535, /* .sendBufferSize, 64k per chunk */ + 65535, /* .recvBufferSize, 64k per chunk */ + 0, /* .maxMessageSize, 0 -> unlimited */ + 0 /* .maxChunkCount, 0 -> unlimited */ +}; + +/***************************/ +/* Default Server Settings */ +/***************************/ + +#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 STRINGIFY(arg) #arg +#define VERSION(MAJOR, MINOR, PATCH, LABEL) \ + STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL + +static UA_StatusCode +createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint, + const UA_ByteString localCertificate) { + UA_EndpointDescription_init(&endpoint->endpointDescription); + + UA_SecurityPolicy_None(&endpoint->securityPolicy, NULL, localCertificate, conf->logger); + endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE; + endpoint->endpointDescription.securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None"); + endpoint->endpointDescription.transportProfileUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"); + + /* Enable all login mechanisms from the access control plugin */ + UA_StatusCode retval = UA_Array_copy(conf->accessControl.userTokenPolicies, + conf->accessControl.userTokenPoliciesSize, + (void **)&endpoint->endpointDescription.userIdentityTokens, + &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + endpoint->endpointDescription.userIdentityTokensSize = + conf->accessControl.userTokenPoliciesSize; + + UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate); + UA_ApplicationDescription_copy(&conf->applicationDescription, + &endpoint->endpointDescription.server); + + return UA_STATUSCODE_GOOD; +} + +void +UA_ServerConfig_set_customHostname(UA_ServerConfig *config, const UA_String customHostname) { + if(!config) + return; + UA_String_deleteMembers(&config->customHostname); + UA_String_copy(&customHostname, &config->customHostname); +} + +#ifdef UA_ENABLE_ENCRYPTION + +static UA_StatusCode +createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf, + UA_Endpoint *endpoint, + UA_MessageSecurityMode securityMode, + const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey) { + UA_EndpointDescription_init(&endpoint->endpointDescription); + + UA_StatusCode retval = + UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, &conf->certificateVerification, + localCertificate, localPrivateKey, conf->logger); + if(retval != UA_STATUSCODE_GOOD) { + endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy); + return retval; + } + + endpoint->endpointDescription.securityMode = securityMode; + endpoint->endpointDescription.securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"); + endpoint->endpointDescription.transportProfileUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"); + + /* Enable all login mechanisms from the access control plugin */ + retval = UA_Array_copy(conf->accessControl.userTokenPolicies, + conf->accessControl.userTokenPoliciesSize, + (void **)&endpoint->endpointDescription.userIdentityTokens, + &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + endpoint->endpointDescription.userIdentityTokensSize = + conf->accessControl.userTokenPoliciesSize; + + UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate); + UA_ApplicationDescription_copy(&conf->applicationDescription, + &endpoint->endpointDescription.server); + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +createSecurityPolicyBasic256Sha256Endpoint(UA_ServerConfig *const conf, + UA_Endpoint *endpoint, + UA_MessageSecurityMode securityMode, + const UA_ByteString localCertificate, + const UA_ByteString localPrivateKey) { + UA_EndpointDescription_init(&endpoint->endpointDescription); + + UA_StatusCode retval = + UA_SecurityPolicy_Basic256Sha256(&endpoint->securityPolicy, &conf->certificateVerification, localCertificate, + localPrivateKey, conf->logger); + if(retval != UA_STATUSCODE_GOOD) { + endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy); + return retval; + } + + endpoint->endpointDescription.securityMode = securityMode; + endpoint->endpointDescription.securityPolicyUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); + endpoint->endpointDescription.transportProfileUri = + UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"); + + /* Enable all login mechanisms from the access control plugin */ + retval = UA_Array_copy(conf->accessControl.userTokenPolicies, + conf->accessControl.userTokenPoliciesSize, + (void **)&endpoint->endpointDescription.userIdentityTokens, + &UA_TYPES[UA_TYPES_USERTOKENPOLICY]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + endpoint->endpointDescription.userIdentityTokensSize = + conf->accessControl.userTokenPoliciesSize; + + UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate); + UA_ApplicationDescription_copy(&conf->applicationDescription, + &endpoint->endpointDescription.server); + + return UA_STATUSCODE_GOOD; +} + +#endif + +const size_t usernamePasswordsSize = 2; +UA_UsernamePasswordLogin usernamePasswords[2] = { + {UA_STRING_STATIC("user1"), UA_STRING_STATIC("password")}, + {UA_STRING_STATIC("user2"), UA_STRING_STATIC("password1")}}; + +static UA_ServerConfig * +createDefaultConfig(void) { + UA_ServerConfig *conf = (UA_ServerConfig *)UA_malloc(sizeof(UA_ServerConfig)); + if(!conf) + return NULL; + + /* Zero out.. All members have a valid initial value */ + memset(conf, 0, sizeof(UA_ServerConfig)); + + /* --> Start setting the default static config <-- */ + conf->nThreads = 1; + conf->logger = UA_Log_Stdout; + + /* Server Description */ + 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)); + conf->buildInfo.buildNumber = UA_STRING_ALLOC(__DATE__ + " " + __TIME__); + conf->buildInfo.buildDate = 0; + + conf->applicationDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI); + 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; */ + +#ifdef UA_ENABLE_DISCOVERY + /* conf->mdnsServerName = UA_STRING_NULL; */ + /* conf->serverCapabilitiesSize = 0; */ + /* conf->serverCapabilities = NULL; */ +#endif + + /* Custom DataTypes */ + /* conf->customDataTypesSize = 0; */ + /* conf->customDataTypes = NULL; */ + + /* Networking */ + /* conf->networkLayersSize = 0; */ + /* conf->networkLayers = NULL; */ + /* conf->customHostname = UA_STRING_NULL; */ + + /* Endpoints */ + /* conf->endpoints = {0, NULL}; */ + + /* Certificate Verification that accepts every certificate. Can be + * overwritten when the policy is specialized. */ + UA_CertificateVerification_AcceptAll(&conf->certificateVerification); + + /* Global Node Lifecycle */ + conf->nodeLifecycle.constructor = NULL; + conf->nodeLifecycle.destructor = NULL; + + /* Access Control. Anonymous Login only. */ + conf->accessControl = UA_AccessControl_default(true, usernamePasswordsSize, usernamePasswords); + + /* Limits for SecureChannels */ + conf->maxSecureChannels = 40; + conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */ + + /* Limits for Sessions */ + conf->maxSessions = 100; + conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */ + + /* 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->maxRetransmissionQueueSize = 0; /* unlimited */ + + /* Limits for MonitoredItems */ + conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0); + conf->queueSizeLimits = UA_UINT32RANGE(1, 100); + +#ifdef UA_ENABLE_DISCOVERY + conf->discoveryCleanupTimeout = 60 * 60; +#endif + + /* --> Finish setting the default static config <-- */ + + return conf; +} + +static UA_StatusCode +addDefaultNetworkLayers(UA_ServerConfig *conf, UA_UInt16 portNumber) { + /* Add a network layer */ + conf->networkLayers = (UA_ServerNetworkLayer *) + UA_malloc(sizeof(UA_ServerNetworkLayer)); + if(!conf->networkLayers) + return UA_STATUSCODE_BADOUTOFMEMORY; + + conf->networkLayers[0] = + UA_ServerNetworkLayerTCP(UA_ConnectionConfig_default, portNumber, conf->logger); + if (!conf->networkLayers[0].handle) + return UA_STATUSCODE_BADOUTOFMEMORY; + conf->networkLayersSize = 1; + + return UA_STATUSCODE_GOOD; +} + +UA_ServerConfig * +UA_ServerConfig_new_minimal(UA_UInt16 portNumber, + const UA_ByteString *certificate) { + UA_ServerConfig *conf = createDefaultConfig(); + + UA_StatusCode retval = UA_Nodestore_default_new(&conf->nodestore); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(addDefaultNetworkLayers(conf, portNumber) != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + /* Allocate the endpoint */ + conf->endpoints = (UA_Endpoint *)UA_malloc(sizeof(UA_Endpoint)); + if(!conf->endpoints) { + UA_ServerConfig_delete(conf); + return NULL; + } + conf->endpointsSize = 1; + + /* Populate the endpoint */ + UA_ByteString localCertificate = UA_BYTESTRING_NULL; + if(certificate) + localCertificate = *certificate; + retval = + createSecurityPolicyNoneEndpoint(conf, &conf->endpoints[0], localCertificate); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + return conf; +} + +#ifdef UA_ENABLE_ENCRYPTION + +UA_ServerConfig * +UA_ServerConfig_new_basic128rsa15(UA_UInt16 portNumber, + const UA_ByteString *certificate, + const UA_ByteString *privateKey, + const UA_ByteString *trustList, + size_t trustListSize, + const UA_ByteString *revocationList, + size_t revocationListSize) { + UA_ServerConfig *conf = createDefaultConfig(); + + UA_StatusCode retval = UA_CertificateVerification_Trustlist(&conf->certificateVerification, + trustList, trustListSize, + revocationList, revocationListSize); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = UA_Nodestore_default_new(&conf->nodestore); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(addDefaultNetworkLayers(conf, portNumber) != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(trustListSize == 0) + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "No CA trust-list provided. Any remote certificate will be accepted."); + + /* Allocate the endpoints */ + conf->endpointsSize = 0; + conf->endpoints = (UA_Endpoint *)UA_malloc(sizeof(UA_Endpoint) * 3); + if(!conf->endpoints) { + UA_ServerConfig_delete(conf); + return NULL; + } + + /* Populate the endpoints */ + ++conf->endpointsSize; + retval = createSecurityPolicyNoneEndpoint(conf, &conf->endpoints[0], *certificate); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + ++conf->endpointsSize; + retval = createSecurityPolicyBasic128Rsa15Endpoint(conf, &conf->endpoints[1], + UA_MESSAGESECURITYMODE_SIGN, *certificate, + *privateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + ++conf->endpointsSize; + retval = createSecurityPolicyBasic128Rsa15Endpoint(conf, &conf->endpoints[2], + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, *certificate, + *privateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + return conf; +} + +UA_ServerConfig * +UA_ServerConfig_new_basic256sha256(UA_UInt16 portNumber, + const UA_ByteString *certificate, + const UA_ByteString *privateKey, + const UA_ByteString *trustList, + size_t trustListSize, + const UA_ByteString *revocationList, + size_t revocationListSize) { + UA_ServerConfig *conf = createDefaultConfig(); + + UA_StatusCode retval = UA_CertificateVerification_Trustlist(&conf->certificateVerification, + trustList, trustListSize, + revocationList, revocationListSize); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = UA_Nodestore_default_new(&conf->nodestore); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(addDefaultNetworkLayers(conf, portNumber) != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(trustListSize == 0) + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "No CA trust-list provided. Any remote certificate will be accepted."); + + /* Allocate the endpoints */ + conf->endpointsSize = 0; + conf->endpoints = (UA_Endpoint *)UA_malloc(sizeof(UA_Endpoint) * 3); + if(!conf->endpoints) { + UA_ServerConfig_delete(conf); + return NULL; + } + + /* Populate the endpoints */ + ++conf->endpointsSize; + retval = createSecurityPolicyNoneEndpoint(conf, &conf->endpoints[0], *certificate); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + ++conf->endpointsSize; + retval = createSecurityPolicyBasic256Sha256Endpoint(conf, &conf->endpoints[1], + UA_MESSAGESECURITYMODE_SIGN, *certificate, + *privateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + ++conf->endpointsSize; + retval = createSecurityPolicyBasic256Sha256Endpoint(conf, &conf->endpoints[2], + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, *certificate, + *privateKey); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + return conf; +} + +UA_ServerConfig * +UA_ServerConfig_new_allSecurityPolicies(UA_UInt16 portNumber, + const UA_ByteString *certificate, + const UA_ByteString *privateKey, + const UA_ByteString *trustList, + size_t trustListSize, + const UA_ByteString *revocationList, + size_t revocationListSize) { + UA_ServerConfig *conf = createDefaultConfig(); + + UA_StatusCode retval = UA_CertificateVerification_Trustlist(&conf->certificateVerification, + trustList, trustListSize, + revocationList, revocationListSize); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = UA_Nodestore_default_new(&conf->nodestore); + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(addDefaultNetworkLayers(conf, portNumber) != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + if(trustListSize == 0) + UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, + "No CA trust-list provided. Any remote certificate will be accepted."); + + /* Allocate the endpoints */ + conf->endpointsSize = 0; + conf->endpoints = (UA_Endpoint *)UA_malloc(sizeof(UA_Endpoint) * 5); + if(!conf->endpoints) { + UA_ServerConfig_delete(conf); + return NULL; + } + + /* Populate the endpoints */ + retval = createSecurityPolicyNoneEndpoint(conf, &conf->endpoints[conf->endpointsSize], *certificate); + ++conf->endpointsSize; + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = createSecurityPolicyBasic128Rsa15Endpoint(conf, &conf->endpoints[conf->endpointsSize], + UA_MESSAGESECURITYMODE_SIGN, *certificate, + *privateKey); + ++conf->endpointsSize; + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = createSecurityPolicyBasic128Rsa15Endpoint(conf, &conf->endpoints[conf->endpointsSize], + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, *certificate, + *privateKey); + ++conf->endpointsSize; + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = createSecurityPolicyBasic256Sha256Endpoint(conf, &conf->endpoints[conf->endpointsSize], + UA_MESSAGESECURITYMODE_SIGN, *certificate, + *privateKey); + ++conf->endpointsSize; + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + retval = createSecurityPolicyBasic256Sha256Endpoint(conf, &conf->endpoints[conf->endpointsSize], + UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, *certificate, + *privateKey); + ++conf->endpointsSize; + if(retval != UA_STATUSCODE_GOOD) { + UA_ServerConfig_delete(conf); + return NULL; + } + + return conf; +} + + +#endif + +void +UA_ServerConfig_delete(UA_ServerConfig *config) { + if(!config) + return; + + /* Server Description */ + UA_BuildInfo_deleteMembers(&config->buildInfo); + UA_ApplicationDescription_deleteMembers(&config->applicationDescription); +#ifdef UA_ENABLE_DISCOVERY + UA_String_deleteMembers(&config->mdnsServerName); + UA_Array_delete(config->serverCapabilities, config->serverCapabilitiesSize, + &UA_TYPES[UA_TYPES_STRING]); + config->serverCapabilities = NULL; + config->serverCapabilitiesSize = 0; +#endif + + /* Nodestore */ + if(config->nodestore.deleteNodestore) + config->nodestore.deleteNodestore(config->nodestore.context); + + /* Custom DataTypes */ + for(size_t i = 0; i < config->customDataTypesSize; ++i) + UA_free(config->customDataTypes[i].members); + UA_free(config->customDataTypes); + config->customDataTypes = NULL; + config->customDataTypesSize = 0; + + /* Networking */ + for(size_t i = 0; i < config->networkLayersSize; ++i) + config->networkLayers[i].deleteMembers(&config->networkLayers[i]); + UA_free(config->networkLayers); + config->networkLayers = NULL; + config->networkLayersSize = 0; + UA_String_deleteMembers(&config->customHostname); + config->customHostname = UA_STRING_NULL; + + for(size_t i = 0; i < config->endpointsSize; ++i) { + UA_SecurityPolicy *policy = &config->endpoints[i].securityPolicy; + policy->deleteMembers(policy); + UA_EndpointDescription_deleteMembers(&config->endpoints[i].endpointDescription); + } + UA_free(config->endpoints); + config->endpoints = NULL; + config->endpointsSize = 0; + + /* Certificate Validation */ + config->certificateVerification.deleteMembers(&config->certificateVerification); + + /* Access Control */ + config->accessControl.deleteMembers(&config->accessControl); + + UA_free(config); +} + +/***************************/ +/* Default Client Settings */ +/***************************/ + +const UA_ClientConfig UA_ClientConfig_default = { + 5000, /* .timeout, 5 seconds */ + 10 * 60 * 1000, /* .secureChannelLifeTime, 10 minutes */ + UA_Log_Stdout, /* .logger */ + { /* .localConnectionConfig */ + 0, /* .protocolVersion */ + 65535, /* .sendBufferSize, 64k per chunk */ + 65535, /* .recvBufferSize, 64k per chunk */ + 0, /* .maxMessageSize, 0 -> unlimited */ + 0 /* .maxChunkCount, 0 -> unlimited */ + }, + UA_ClientConnectionTCP, /* .connectionFunc */ + + 0, /* .customDataTypesSize */ + NULL, /*.customDataTypes */ + + NULL, /*.stateCallback */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + NULL, /*.subscriptionInactivityCallback */ +#endif + NULL, /*.inactivityCallback */ + NULL, /*.clientContext */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + 10, /* .outStandingPublishRequests */ +#endif + 0 /* .connectivityCheckInterval */ +}; + +UA_ClientConfig UA_Server_getClientConfig(void) +{ + return UA_ClientConfig_default; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/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 + */ + + +static UA_StatusCode +verify_none(const UA_SecurityPolicy *securityPolicy, + void *channelContext, + const UA_ByteString *message, + const UA_ByteString *signature) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +sign_none(const UA_SecurityPolicy *securityPolicy, + void *channelContext, + const UA_ByteString *message, + UA_ByteString *signature) { + return UA_STATUSCODE_GOOD; +} + +static size_t +length_none(const UA_SecurityPolicy *securityPolicy, + const void *channelContext) { + return 0; +} + +static UA_StatusCode +encrypt_none(const UA_SecurityPolicy *securityPolicy, + void *channelContext, + UA_ByteString *data) { + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +decrypt_none(const UA_SecurityPolicy *securityPolicy, + 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(const UA_SecurityPolicy *securityPolicy, + 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(const UA_SecurityPolicy *securityPolicy, UA_ByteString *out) { + if(securityPolicy == NULL || out == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Fill blocks of four byte */ + size_t i = 0; + while(i + 3 < out->length) { + UA_UInt32 rand = UA_UInt32_random(); + memcpy(&out->data[i], &rand, 4); + i = i+4; + } + + /* Fill the remaining byte */ + UA_UInt32 rand = UA_UInt32_random(); + memcpy(&out->data[i], &rand, out->length % 4); + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +newContext_none(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **channelContext) { + return UA_STATUSCODE_GOOD; +} + +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 void +policy_deletemembers_none(UA_SecurityPolicy *policy) { + UA_ByteString_deleteMembers(&policy->localCertificate); +} + +UA_StatusCode +UA_SecurityPolicy_None(UA_SecurityPolicy *policy, UA_CertificateVerification *certificateVerification, + const UA_ByteString localCertificate, UA_Logger logger) { + policy->policyContext = (void *)(uintptr_t)logger; + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); + policy->logger = logger; + UA_ByteString_copy(&localCertificate, &policy->localCertificate); + + policy->certificateVerification = certificateVerification; + + policy->symmetricModule.generateKey = generateKey_none; + policy->symmetricModule.generateNonce = generateNonce_none; + + 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; + + UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm = + &policy->symmetricModule.cryptoModule.encryptionAlgorithm; + 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; + + 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->deleteMembers = policy_deletemembers_none; + + return UA_STATUSCODE_GOOD; +} + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB + */ + + +#ifdef UA_ENABLE_ENCRYPTION + +#include <mbedtls/aes.h> +#include <mbedtls/md.h> +#include <mbedtls/x509_crt.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/entropy.h> +#include <mbedtls/entropy_poll.h> +#include <mbedtls/error.h> +#include <mbedtls/version.h> +#include <mbedtls/sha1.h> + + +/* Notes: + * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to + * allocate temp buffers. + * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer + */ + +#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN 11 +#define UA_SHA1_LENGTH 20 +#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH 16 +#define UA_BASIC128RSA15_SYM_SIGNING_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_MINASYMKEYLENGTH 128 +#define UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH 256 + +#define UA_LOG_MBEDERR \ + char errBuff[300]; \ + mbedtls_strerror(mbedErr, errBuff, 300); \ + UA_LOG_WARNING(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, \ + "mbedTLS returned an error: %s", errBuff); \ + +#define UA_MBEDTLS_ERRORHANDLING(errorcode) \ + if(mbedErr) { \ + UA_LOG_MBEDERR \ + retval = errorcode; \ + } + +#define UA_MBEDTLS_ERRORHANDLING_RETURN(errorcode) \ + if(mbedErr) { \ + UA_LOG_MBEDERR \ + return errorcode; \ + } + +typedef struct { + const UA_SecurityPolicy *securityPolicy; + UA_ByteString localCertThumbprint; + + mbedtls_ctr_drbg_context drbgContext; + mbedtls_entropy_context entropyContext; + mbedtls_md_context_t sha1MdContext; + mbedtls_pk_context localPrivateKey; +} Basic128Rsa15_PolicyContext; + +typedef struct { + Basic128Rsa15_PolicyContext *policyContext; + + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; + + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; + + mbedtls_x509_crt remoteCertificate; +} Basic128Rsa15_ChannelContext; + + +/********************/ +/* AsymmetricModule */ +/********************/ + +static UA_StatusCode +asym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + /* 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 + + /* Set the RSA settings */ + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); + + /* Verify */ + int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk, + MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH, + signature->data, signature->length); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +asym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *message, + UA_ByteString *signature) { + if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + 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 + + Basic128Rsa15_PolicyContext *pc = cc->policyContext; + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey); + mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); + + size_t sigLen = 0; + int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey, + MBEDTLS_MD_SHA1, hash, + UA_SHA1_LENGTH, signature->data, + &sigLen, mbedtls_ctr_drbg_random, + &pc->drbgContext); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR); + return UA_STATUSCODE_GOOD; +} + +static size_t +asym_getLocalSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const Basic128Rsa15_ChannelContext *cc) { + if(securityPolicy == NULL || cc == NULL) + return 0; + + return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len; +} + +static size_t +asym_getRemoteSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const Basic128Rsa15_ChannelContext *cc) { + if(securityPolicy == NULL || cc == NULL) + return 0; + + return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +} + +static UA_StatusCode +asym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + Basic128Rsa15_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemotePlainTextBlockSize(securityPolicy, cc); + + 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); + + 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(retval != UA_STATUSCODE_GOOD) + return retval; + + size_t lenDataToEncrypt = data->length; + size_t inOffset = 0; + size_t offset = 0; + size_t outLength = 0; + Basic128Rsa15_PolicyContext *pc = cc->policyContext; + while(lenDataToEncrypt >= plainTextBlockSize) { + int mbedErr = mbedtls_pk_encrypt(&cc->remoteCertificate.pk, + data->data + inOffset, plainTextBlockSize, + encrypted.data + offset, &outLength, + encrypted.length - offset, + mbedtls_ctr_drbg_random, + &pc->drbgContext); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADINTERNALERROR); + if(retval != UA_STATUSCODE_GOOD) { + UA_ByteString_deleteMembers(&encrypted); + return retval; + } + + inOffset += plainTextBlockSize; + offset += outLength; + lenDataToEncrypt -= plainTextBlockSize; + } + + memcpy(data->data, encrypted.data, offset); + UA_ByteString_deleteMembers(&encrypted); + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +asym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + Basic128Rsa15_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || 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); + + if(data->length % rsaContext->len != 0) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString decrypted; + UA_StatusCode retval = UA_ByteString_allocBuffer(&decrypted, data->length); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + size_t lenDataToDecrypt = data->length; + size_t inOffset = 0; + size_t offset = 0; + size_t outLength = 0; + while(lenDataToDecrypt >= rsaContext->len) { + int mbedErr = mbedtls_pk_decrypt(&cc->policyContext->localPrivateKey, + data->data + inOffset, rsaContext->len, + decrypted.data + offset, &outLength, + decrypted.length - offset, NULL, NULL); + if(mbedErr) + UA_ByteString_deleteMembers(&decrypted); // TODO: Maybe change error macro to jump to cleanup? + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + + inOffset += rsaContext->len; + offset += outLength; + lenDataToDecrypt -= rsaContext->len; + } + + if(lenDataToDecrypt == 0) { + memcpy(data->data, decrypted.data, offset); + data->length = offset; + } else { + retval = UA_STATUSCODE_BADINTERNALERROR; + } + + UA_ByteString_deleteMembers(&decrypted); + return retval; +} + +static size_t +asym_getRemoteEncryptionKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + 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) { + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len; +} + +static size_t +asym_getRemotePlainTextBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const Basic128Rsa15_ChannelContext *cc) { + mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + return rsaContext->len - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN; +} + +static UA_StatusCode +asym_makeThumbprint_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificate, + UA_ByteString *thumbprint) { + if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL)) + return UA_STATUSCODE_BADINTERNALERROR; + + if(thumbprint->length != UA_SHA1_LENGTH) + return UA_STATUSCODE_BADINTERNALERROR; + +#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; +} + +static UA_StatusCode +asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) { + if(securityPolicy == NULL || certificateThumbprint == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) + return UA_STATUSCODE_BADCERTIFICATEINVALID; + + return UA_STATUSCODE_GOOD; +} + +/*******************/ +/* SymmetricModule */ +/*******************/ + +static void +md_hmac(mbedtls_md_context_t *context, const UA_ByteString *key, + const UA_ByteString *in, unsigned char out[20]) { + 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 UA_StatusCode +sym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(securityPolicy == NULL || 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"); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + + Basic128Rsa15_PolicyContext *pc = + (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; + + unsigned char mac[UA_SHA1_LENGTH]; + md_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac); + + /* Compare with Signature */ + if(memcmp(signature->data, mac, UA_SHA1_LENGTH) != 0) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +sym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *message, + UA_ByteString *signature) { + if(signature->length != UA_SHA1_LENGTH) + return UA_STATUSCODE_BADINTERNALERROR; + + md_hmac(&cc->policyContext->sha1MdContext, &cc->localSymSigningKey, + message, signature->data); + return UA_STATUSCODE_GOOD; +} + +static size_t +sym_getSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const void *channelContext) { + return UA_SHA1_LENGTH; +} + +static size_t +sym_getSigningKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy, + 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) { + return UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH; +} + +static size_t +sym_getEncryptionBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy, + 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) { + return UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE; +} + +static UA_StatusCode +sym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const Basic128Rsa15_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + if(cc->localSymIv.length != + securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc)) + 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."); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* 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); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR); + + 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); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADINTERNALERROR); + UA_ByteString_deleteMembers(&ivCopy); + return retval; +} + +static UA_StatusCode +sym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const Basic128Rsa15_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + size_t encryptionBlockSize = + securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc); + + 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."); + 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); + UA_MBEDTLS_ERRORHANDLING_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); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADINTERNALERROR); + UA_ByteString_deleteMembers(&ivCopy); + return retval; +} + +static void +swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) { + UA_ByteString tmp = *bufA; + *bufA = *bufB; + *bufB = tmp; +} + +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) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic128Rsa15_PolicyContext *pc = + (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; + + size_t hashLen = 0; + const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + hashLen = (size_t)mbedtls_md_get_size(mdInfo); + + 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_ByteString ANext_and_seed; + UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length); + memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length); + + UA_ByteString A = { + hashLen, + A_and_seed.data + }; + + UA_ByteString ANext = { + hashLen, + ANext_and_seed.data + }; + + md_hmac(&pc->sha1MdContext, secret, seed, A.data); + + 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; + } + + md_hmac(&pc->sha1MdContext, secret, &A_and_seed, outSegment.data); + md_hmac(&pc->sha1MdContext, secret, &A, ANext.data); + + 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; + } + + if(bufferAllocated) { + memcpy(out->data + offset, outSegment.data, out->length - offset); + UA_ByteString_deleteMembers(&outSegment); + } + + swapBuffers(&ANext_and_seed, &A_and_seed); + swapBuffers(&ANext, &A); + } + + UA_ByteString_deleteMembers(&A_and_seed); + UA_ByteString_deleteMembers(&ANext_and_seed); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +sym_generateNonce_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + UA_ByteString *out) { + if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic128Rsa15_PolicyContext *data = + (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; + + int mbedErr = mbedtls_ctr_drbg_random(&data->drbgContext, out->data, out->length); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADUNEXPECTEDERROR); + + return UA_STATUSCODE_GOOD; +} + +/*****************/ +/* ChannelModule */ +/*****************/ + +/* Assumes that the certificate has been verified externally */ +static UA_StatusCode +parseRemoteCertificate_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *remoteCertificate) { + if(remoteCertificate == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const UA_SecurityPolicy *securityPolicy = cc->policyContext->securityPolicy; + + /* Parse the certificate */ + int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data, + remoteCertificate->length); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + + /* Check the key length */ + 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; + + 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); + + mbedtls_x509_crt_free(&cc->remoteCertificate); + + UA_free(cc); +} + +static UA_StatusCode +channelContext_newContext_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **pp_contextData) { + if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Allocate the channel context */ + *pp_contextData = UA_malloc(sizeof(Basic128Rsa15_ChannelContext)); + if(*pp_contextData == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + + Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)*pp_contextData; + + /* Initialize the channel context */ + cc->policyContext = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext; + + UA_ByteString_init(&cc->localSymSigningKey); + UA_ByteString_init(&cc->localSymEncryptingKey); + UA_ByteString_init(&cc->localSymIv); + + UA_ByteString_init(&cc->remoteSymSigningKey); + UA_ByteString_init(&cc->remoteSymEncryptingKey); + UA_ByteString_init(&cc->remoteSymIv); + + mbedtls_x509_crt_init(&cc->remoteCertificate); + + // TODO: this can be optimized so that we dont allocate memory before parsing the certificate + UA_StatusCode retval = parseRemoteCertificate_sp_basic128rsa15(cc, remoteCertificate); + if(retval != UA_STATUSCODE_GOOD) { + channelContext_deleteContext_sp_basic128rsa15(cc); + *pp_contextData = NULL; + } + return retval; +} + +static UA_StatusCode +channelContext_setLocalSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); +} + +static UA_StatusCode +channelContext_setLocalSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); +} + + +static UA_StatusCode +channelContext_setLocalSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *iv) { + if(iv == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); +} + +static UA_StatusCode +channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +} + +static UA_StatusCode +channelContext_setRemoteSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +} + +static UA_StatusCode +channelContext_setRemoteSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *iv) { + if(iv == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->remoteSymIv); + return UA_ByteString_copy(iv, &cc->remoteSymIv); +} + +static UA_StatusCode +channelContext_compareCertificate_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc, + const UA_ByteString *certificate) { + if(cc == NULL || certificate == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const UA_SecurityPolicy *securityPolicy = cc->policyContext->securityPolicy; + + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); + int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length); + if(mbedErr) { + UA_LOG_MBEDERR; + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + + 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; + + mbedtls_x509_crt_free(&cert); + return retval; +} + +static void +deleteMembers_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) { + if(securityPolicy == NULL) + return; + + if(securityPolicy->policyContext == NULL) + return; + + UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + + /* delete all allocated members in the context */ + Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *) + securityPolicy->policyContext; + + mbedtls_ctr_drbg_free(&pc->drbgContext); + mbedtls_entropy_free(&pc->entropyContext); + mbedtls_pk_free(&pc->localPrivateKey); + mbedtls_md_free(&pc->sha1MdContext); + UA_ByteString_deleteMembers(&pc->localCertThumbprint); + + UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Deleted members of EndpointContext for sp_basic128rsa15"); + + UA_free(pc); + securityPolicy->policyContext = NULL; +} + +static UA_StatusCode +policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy, + const UA_ByteString localPrivateKey) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(securityPolicy == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *) + UA_malloc(sizeof(Basic128Rsa15_PolicyContext)); + securityPolicy->policyContext = (void *)pc; + if(!pc) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + goto error; + } + + /* Initialize the PolicyContext */ + memset(pc, 0, sizeof(Basic128Rsa15_PolicyContext)); + mbedtls_ctr_drbg_init(&pc->drbgContext); + mbedtls_entropy_init(&pc->entropyContext); + mbedtls_pk_init(&pc->localPrivateKey); + mbedtls_md_init(&pc->sha1MdContext); + pc->securityPolicy = securityPolicy; + + /* Initialized the message digest */ + const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADOUTOFMEMORY); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + /* Add the system entropy source */ + mbedErr = mbedtls_entropy_add_source(&pc->entropyContext, + mbedtls_platform_entropy_poll, NULL, 0, + MBEDTLS_ENTROPY_SOURCE_STRONG); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + /* Seed the RNG */ + char *personalization = "open62541-drbg"; + mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func, + &pc->entropyContext, + (const unsigned char *)personalization, 14); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + /* Set the private key */ + mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, + localPrivateKey.data, localPrivateKey.length, + NULL, 0); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + if(retval != UA_STATUSCODE_GOOD) + 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_basic128rsa15(pc->securityPolicy, + &securityPolicy->localCertificate, + &pc->localCertThumbprint); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + return UA_STATUSCODE_GOOD; + +error: + UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Could not create securityContext"); + if(securityPolicy->policyContext != NULL) + deleteMembers_sp_basic128rsa15(securityPolicy); + return retval; +} + +UA_StatusCode +UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, UA_CertificateVerification *certificateVerification, + const UA_ByteString localCertificate, const UA_ByteString localPrivateKey, + UA_Logger logger) { + memset(policy, 0, sizeof(UA_SecurityPolicy)); + policy->logger = logger; + + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"); + + UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule; + + /* Copy the certificate and add a NULL to the end */ + UA_StatusCode retval = + UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1); + if(retval != UA_STATUSCODE_GOOD) + return retval; + memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length); + policy->localCertificate.data[localCertificate.length] = '\0'; + policy->localCertificate.length--; + policy->certificateVerification = certificateVerification; + + /* AsymmetricModule */ + UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm = + &asymmetricModule->cryptoModule.signatureAlgorithm; + 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; + asym_signatureAlgorithm->sign = + (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, + const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic128rsa15; + asym_signatureAlgorithm->getLocalSignatureSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic128rsa15; + asym_signatureAlgorithm->getRemoteSignatureSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic128rsa15; + asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function + asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function + + UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm = + &asymmetricModule->cryptoModule.encryptionAlgorithm; + asym_encryptionAlgorithm->uri = UA_STRING("TODO: ALG URI"); + asym_encryptionAlgorithm->encrypt = + (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15; + asym_encryptionAlgorithm->decrypt = + (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *)) + asym_decrypt_sp_basic128rsa15; + asym_encryptionAlgorithm->getLocalKeyLength = NULL; // TODO: Write function + 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 + asym_encryptionAlgorithm->getRemotePlainTextBlockSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic128rsa15; + + asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic128rsa15; + asymmetricModule->compareCertificateThumbprint = + asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15; + + /* SymmetricModule */ + symmetricModule->generateKey = sym_generateKey_sp_basic128rsa15; + symmetricModule->generateNonce = sym_generateNonce_sp_basic128rsa15; + + 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 (*)(const UA_SecurityPolicy *, 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; + 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; + sym_signatureAlgorithm->getRemoteKeyLength = + (size_t (*)(const UA_SecurityPolicy *, + 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; + sym_encryptionAlgorithm->decrypt = + (UA_StatusCode(*)(const UA_SecurityPolicy *, 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; + sym_encryptionAlgorithm->getRemotePlainTextBlockSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic128rsa15; + symmetricModule->secureChannelNonceLength = 16; + + // Use the same signature algorithm as the asymmetric component for certificate signing (see standard) + policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + + /* ChannelModule */ + channelModule->newContext = channelContext_newContext_sp_basic128rsa15; + channelModule->deleteContext = (void (*)(void *)) + channelContext_deleteContext_sp_basic128rsa15; + + channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymEncryptingKey_sp_basic128rsa15; + channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymSigningKey_sp_basic128rsa15; + channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymIv_sp_basic128rsa15; + + channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15; + channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymSigningKey_sp_basic128rsa15; + channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymIv_sp_basic128rsa15; + + channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *)) + channelContext_compareCertificate_sp_basic128rsa15; + + policy->deleteMembers = deleteMembers_sp_basic128rsa15; + + return policyContext_newContext_sp_basic128rsa15(policy, localPrivateKey); +} + +#endif /* UA_ENABLE_ENCRYPTION */ + +/*********************************** amalgamated original file "/home/jvoe/open62541/plugins/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 + * 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 + */ + + +#ifdef UA_ENABLE_ENCRYPTION + +#include <mbedtls/aes.h> +#include <mbedtls/md.h> +#include <mbedtls/sha256.h> +#include <mbedtls/x509_crt.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/entropy.h> +#include <mbedtls/entropy_poll.h> +#include <mbedtls/error.h> +#include <mbedtls/version.h> +#include <mbedtls/sha1.h> + + +/* Notes: + * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to + * allocate temp buffers. + * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer + */ + +#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42 +#define UA_SHA1_LENGTH 20 +#define UA_SHA256_LENGTH 32 +#define UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32 +#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_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 + +#define UA_LOG_MBEDERR \ + char errBuff[300]; \ + mbedtls_strerror(mbedErr, errBuff, 300); \ + UA_LOG_WARNING(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, \ + "mbedTLS returned an error: %s", errBuff); \ + +#define UA_MBEDTLS_ERRORHANDLING(errorcode) \ + if(mbedErr) { \ + UA_LOG_MBEDERR \ + retval = errorcode; \ + } + +#define UA_MBEDTLS_ERRORHANDLING_RETURN(errorcode) \ + if(mbedErr) { \ + UA_LOG_MBEDERR \ + return errorcode; \ + } + +typedef struct { + const UA_SecurityPolicy *securityPolicy; + UA_ByteString localCertThumbprint; + + mbedtls_ctr_drbg_context drbgContext; + mbedtls_entropy_context entropyContext; + mbedtls_md_context_t sha256MdContext; + mbedtls_pk_context localPrivateKey; +} Basic256Sha256_PolicyContext; + +typedef struct { + Basic256Sha256_PolicyContext *policyContext; + + UA_ByteString localSymSigningKey; + UA_ByteString localSymEncryptingKey; + UA_ByteString localSymIv; + + UA_ByteString remoteSymSigningKey; + UA_ByteString remoteSymEncryptingKey; + UA_ByteString remoteSymIv; + + mbedtls_x509_crt remoteCertificate; +} Basic256Sha256_ChannelContext; + +/********************/ +/* AsymmetricModule */ +/********************/ + +/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ +static UA_StatusCode +asym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + Basic256Sha256_ChannelContext *cc, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + unsigned char hash[UA_SHA256_LENGTH]; +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 + // TODO check return status + mbedtls_sha256_ret(message->data, message->length, hash, 0); +#else + mbedtls_sha256(message->data, message->length, hash, 0); +#endif + + /* 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); + + /* 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_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + return UA_STATUSCODE_GOOD; +} + +/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */ +static UA_StatusCode +asym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + Basic256Sha256_ChannelContext *cc, + const UA_ByteString *message, + UA_ByteString *signature) { + if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + unsigned char hash[UA_SHA256_LENGTH]; +#if MBEDTLS_VERSION_NUMBER >= 0x02070000 + // TODO check return status + mbedtls_sha256_ret(message->data, message->length, hash, 0); +#else + mbedtls_sha256(message->data, message->length, hash, 0); +#endif + + Basic256Sha256_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); + + size_t sigLen = 0; + + /* 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, + &sigLen, mbedtls_ctr_drbg_random, + &pc->drbgContext); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR); + return UA_STATUSCODE_GOOD; +} + +static size_t +asym_getLocalSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const Basic256Sha256_ChannelContext *cc) { + if(securityPolicy == NULL || cc == NULL) + return 0; + + return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len; +} + +static size_t +asym_getRemoteSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const Basic256Sha256_ChannelContext *cc) { + if(securityPolicy == NULL || cc == NULL) + return 0; + + return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len; +} + +/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ +static UA_StatusCode +asym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + Basic256Sha256_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemotePlainTextBlockSize(securityPolicy, cc); + + 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_V21, MBEDTLS_MD_SHA1); + + 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(retval != UA_STATUSCODE_GOOD) + return retval; + + size_t lenDataToEncrypt = data->length; + size_t inOffset = 0; + size_t offset = 0; + const unsigned char *label = NULL; + Basic256Sha256_PolicyContext *pc = cc->policyContext; + while(lenDataToEncrypt >= plainTextBlockSize) { + int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(remoteRsaContext, mbedtls_ctr_drbg_random, + &pc->drbgContext, MBEDTLS_RSA_PUBLIC, + label, 0, plainTextBlockSize, + data->data + inOffset, encrypted.data + offset); + + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADINTERNALERROR); + if(retval != UA_STATUSCODE_GOOD) { + UA_ByteString_deleteMembers(&encrypted); + return retval; + } + + inOffset += plainTextBlockSize; + offset += remoteRsaContext->len; + lenDataToEncrypt -= plainTextBlockSize; + } + + memcpy(data->data, encrypted.data, offset); + UA_ByteString_deleteMembers(&encrypted); + + return UA_STATUSCODE_GOOD; +} + +/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */ +static UA_StatusCode +asym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + Basic256Sha256_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || 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_V21, MBEDTLS_MD_SHA1); + + if(data->length % rsaContext->len != 0) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString decrypted; + UA_StatusCode retval = UA_ByteString_allocBuffer(&decrypted, data->length); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + size_t lenDataToDecrypt = data->length; + size_t inOffset = 0; + size_t offset = 0; + size_t outLength = 0; + const unsigned char *label = NULL; + Basic256Sha256_PolicyContext *pc = cc->policyContext; + + while(lenDataToDecrypt >= rsaContext->len) { + int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random, + &pc->drbgContext, MBEDTLS_RSA_PRIVATE, + label, 0, &outLength, + data->data + inOffset, + decrypted.data + offset, + decrypted.length - offset); + if(mbedErr) + UA_ByteString_deleteMembers(&decrypted); // TODO: Maybe change error macro to jump to cleanup? + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + + inOffset += rsaContext->len; + offset += outLength; + lenDataToDecrypt -= rsaContext->len; + } + + if(lenDataToDecrypt == 0) { + memcpy(data->data, decrypted.data, offset); + data->length = offset; + } else { + retval = UA_STATUSCODE_BADINTERNALERROR; + } + + UA_ByteString_deleteMembers(&decrypted); + return retval; +} + +static size_t +asym_getRemoteEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + 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, + UA_ByteString *thumbprint) { + if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL)) + return UA_STATUSCODE_BADINTERNALERROR; + + if(thumbprint->length != UA_SHA1_LENGTH) + return UA_STATUSCODE_BADINTERNALERROR; + + /* 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; +} + +static UA_StatusCode +asymmetricModule_compareCertificateThumbprint_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *certificateThumbprint) { + if(securityPolicy == NULL || certificateThumbprint == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) + return UA_STATUSCODE_BADCERTIFICATEINVALID; + + return UA_STATUSCODE_GOOD; +} + +/*******************/ +/* SymmetricModule */ +/*******************/ + +static void +md_hmac_Basic256Sha256(mbedtls_md_context_t *context, const UA_ByteString *key, + const UA_ByteString *in, unsigned char out[32]) { + 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 UA_StatusCode +sym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + Basic256Sha256_ChannelContext *cc, + const UA_ByteString *message, + const UA_ByteString *signature) { + if(securityPolicy == NULL || 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"); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + + Basic256Sha256_PolicyContext *pc = + (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + + unsigned char mac[UA_SHA256_LENGTH]; + md_hmac_Basic256Sha256(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac); + + /* Compare with Signature */ + if(memcmp(signature->data, mac, UA_SHA256_LENGTH) != 0) + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +sym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const Basic256Sha256_ChannelContext *cc, + const UA_ByteString *message, + UA_ByteString *signature) { + if(signature->length != UA_SHA256_LENGTH) + return UA_STATUSCODE_BADINTERNALERROR; + + md_hmac_Basic256Sha256(&cc->policyContext->sha256MdContext, &cc->localSymSigningKey, + message, signature->data); + return UA_STATUSCODE_GOOD; +} + +static size_t +sym_getSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const void *channelContext) { + return UA_SHA256_LENGTH; +} + +static size_t +sym_getSigningKeyLength_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy, + const void *const channelContext) { + return UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH; +} + +static size_t +sym_getEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + 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) { + return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE; +} + +static size_t +sym_getPlainTextBlockSize_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy, + const void *const 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, + UA_ByteString *data) { + if(securityPolicy == NULL || cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + if(cc->localSymIv.length != + securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc)) + 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."); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* 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); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR); + + 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); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADINTERNALERROR); + UA_ByteString_deleteMembers(&ivCopy); + return retval; +} + +static UA_StatusCode +sym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const Basic256Sha256_ChannelContext *cc, + UA_ByteString *data) { + if(securityPolicy == NULL || cc == NULL || data == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + size_t encryptionBlockSize = + securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc); + + 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."); + 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); + UA_MBEDTLS_ERRORHANDLING_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); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADINTERNALERROR); + UA_ByteString_deleteMembers(&ivCopy); + return retval; +} + +static void +swapBuffers_Basic256Sha256(UA_ByteString *const bufA, UA_ByteString *const bufB) { + UA_ByteString tmp = *bufA; + *bufA = *bufB; + *bufB = tmp; +} + +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) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic256Sha256_PolicyContext *pc = + (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + + size_t hashLen = 0; + const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + hashLen = (size_t)mbedtls_md_get_size(mdInfo); + + 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_ByteString ANext_and_seed; + UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length); + memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length); + + UA_ByteString A = { + hashLen, + A_and_seed.data + }; + + UA_ByteString ANext = { + hashLen, + ANext_and_seed.data + }; + + md_hmac_Basic256Sha256(&pc->sha256MdContext, secret, seed, A.data); + + 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; + } + + md_hmac_Basic256Sha256(&pc->sha256MdContext, secret, &A_and_seed, outSegment.data); + md_hmac_Basic256Sha256(&pc->sha256MdContext, secret, &A, ANext.data); + + 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; + } + + if(bufferAllocated) { + memcpy(out->data + offset, outSegment.data, out->length - offset); + UA_ByteString_deleteMembers(&outSegment); + } + + swapBuffers_Basic256Sha256(&ANext_and_seed, &A_and_seed); + swapBuffers_Basic256Sha256(&ANext, &A); + } + + UA_ByteString_deleteMembers(&A_and_seed); + UA_ByteString_deleteMembers(&ANext_and_seed); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +sym_generateNonce_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + UA_ByteString *out) { + if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic256Sha256_PolicyContext *data = + (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + + int mbedErr = mbedtls_ctr_drbg_random(&data->drbgContext, out->data, out->length); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADUNEXPECTEDERROR); + + return UA_STATUSCODE_GOOD; +} + +/*****************/ +/* ChannelModule */ +/*****************/ + +/* Assumes that the certificate has been verified externally */ +static UA_StatusCode +parseRemoteCertificate_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *remoteCertificate) { + if(remoteCertificate == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const UA_SecurityPolicy *securityPolicy = cc->policyContext->securityPolicy; + + /* Parse the certificate */ + int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data, + remoteCertificate->length); + UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + + /* Check the key length */ + mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk); + if(rsaContext->len < UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH || + rsaContext->len > UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH) + return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED; + + return UA_STATUSCODE_GOOD; +} + +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_deleteMembers(&cc->remoteSymSigningKey); + UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); + UA_ByteString_deleteMembers(&cc->remoteSymIv); + + mbedtls_x509_crt_free(&cc->remoteCertificate); + + UA_free(cc); +} + +static UA_StatusCode +channelContext_newContext_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate, + void **pp_contextData) { + if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Allocate the channel context */ + *pp_contextData = UA_malloc(sizeof(Basic256Sha256_ChannelContext)); + if(*pp_contextData == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + + Basic256Sha256_ChannelContext *cc = (Basic256Sha256_ChannelContext *)*pp_contextData; + + /* Initialize the channel context */ + cc->policyContext = (Basic256Sha256_PolicyContext *)securityPolicy->policyContext; + + UA_ByteString_init(&cc->localSymSigningKey); + UA_ByteString_init(&cc->localSymEncryptingKey); + UA_ByteString_init(&cc->localSymIv); + + UA_ByteString_init(&cc->remoteSymSigningKey); + UA_ByteString_init(&cc->remoteSymEncryptingKey); + UA_ByteString_init(&cc->remoteSymIv); + + mbedtls_x509_crt_init(&cc->remoteCertificate); + + // TODO: this can be optimized so that we dont allocate memory before parsing the certificate + UA_StatusCode retval = parseRemoteCertificate_sp_basic256sha256(cc, remoteCertificate); + if(retval != UA_STATUSCODE_GOOD) { + channelContext_deleteContext_sp_basic256sha256(cc); + *pp_contextData = NULL; + } + return retval; +} + +static UA_StatusCode +channelContext_setLocalSymEncryptingKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->localSymEncryptingKey); + return UA_ByteString_copy(key, &cc->localSymEncryptingKey); +} + +static UA_StatusCode +channelContext_setLocalSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->localSymSigningKey); + return UA_ByteString_copy(key, &cc->localSymSigningKey); +} + + +static UA_StatusCode +channelContext_setLocalSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *iv) { + if(iv == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->localSymIv); + return UA_ByteString_copy(iv, &cc->localSymIv); +} + +static UA_StatusCode +channelContext_setRemoteSymEncryptingKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey); + return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey); +} + +static UA_StatusCode +channelContext_setRemoteSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *key) { + if(key == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->remoteSymSigningKey); + return UA_ByteString_copy(key, &cc->remoteSymSigningKey); +} + +static UA_StatusCode +channelContext_setRemoteSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc, + const UA_ByteString *iv) { + if(iv == NULL || cc == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_ByteString_deleteMembers(&cc->remoteSymIv); + return UA_ByteString_copy(iv, &cc->remoteSymIv); +} + +static UA_StatusCode +channelContext_compareCertificate_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc, + const UA_ByteString *certificate) { + if(cc == NULL || certificate == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + const UA_SecurityPolicy *securityPolicy = cc->policyContext->securityPolicy; + + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); + int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length); + if(mbedErr) { + UA_LOG_MBEDERR; + return UA_STATUSCODE_BADSECURITYCHECKSFAILED; + } + + 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; + + mbedtls_x509_crt_free(&cert); + return retval; +} + +static void +deleteMembers_sp_basic256sha256(UA_SecurityPolicy *securityPolicy) { + if(securityPolicy == NULL) + return; + + if(securityPolicy->policyContext == NULL) + return; + + UA_ByteString_deleteMembers(&securityPolicy->localCertificate); + + /* delete all allocated members in the context */ + Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *) + securityPolicy->policyContext; + + mbedtls_ctr_drbg_free(&pc->drbgContext); + mbedtls_entropy_free(&pc->entropyContext); + mbedtls_pk_free(&pc->localPrivateKey); + mbedtls_md_free(&pc->sha256MdContext); + UA_ByteString_deleteMembers(&pc->localCertThumbprint); + + UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Deleted members of EndpointContext for sp_basic256sha256"); + + UA_free(pc); + securityPolicy->policyContext = NULL; +} + +static UA_StatusCode +policyContext_newContext_sp_basic256sha256(UA_SecurityPolicy *securityPolicy, + const UA_ByteString localPrivateKey) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(securityPolicy == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + + Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *) + UA_malloc(sizeof(Basic256Sha256_PolicyContext)); + securityPolicy->policyContext = (void *)pc; + if(!pc) { + retval = UA_STATUSCODE_BADOUTOFMEMORY; + goto error; + } + + /* Initialize the PolicyContext */ + memset(pc, 0, sizeof(Basic256Sha256_PolicyContext)); + mbedtls_ctr_drbg_init(&pc->drbgContext); + mbedtls_entropy_init(&pc->entropyContext); + mbedtls_pk_init(&pc->localPrivateKey); + mbedtls_md_init(&pc->sha256MdContext); + pc->securityPolicy = securityPolicy; + + /* 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); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADOUTOFMEMORY); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + /* Add the system entropy source */ + mbedErr = mbedtls_entropy_add_source(&pc->entropyContext, + mbedtls_platform_entropy_poll, NULL, 0, + MBEDTLS_ENTROPY_SOURCE_STRONG); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + /* Seed the RNG */ + char *personalization = "open62541-drbg"; + mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func, + &pc->entropyContext, + (const unsigned char *)personalization, 14); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + /* Set the private key */ + mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, + localPrivateKey.data, localPrivateKey.length, + NULL, 0); + UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED); + if(retval != UA_STATUSCODE_GOOD) + 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_basic256sha256(pc->securityPolicy, + &securityPolicy->localCertificate, + &pc->localCertThumbprint); + if(retval != UA_STATUSCODE_GOOD) + goto error; + + return UA_STATUSCODE_GOOD; + +error: + UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Could not create securityContext"); + if(securityPolicy->policyContext != NULL) + deleteMembers_sp_basic256sha256(securityPolicy); + return retval; +} + +UA_StatusCode +UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, UA_CertificateVerification *certificateVerification, + const UA_ByteString localCertificate, const UA_ByteString localPrivateKey, + UA_Logger logger) { + memset(policy, 0, sizeof(UA_SecurityPolicy)); + policy->logger = logger; + + policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); + + UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule; + UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule; + UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule; + + /* Copy the certificate and add a NULL to the end */ + UA_StatusCode retval = + UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1); + if(retval != UA_STATUSCODE_GOOD) + return retval; + memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length); + policy->localCertificate.data[localCertificate.length] = '\0'; + policy->localCertificate.length--; + policy->certificateVerification = certificateVerification; + + /* 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 (*)(const UA_SecurityPolicy *, 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; + asym_signatureAlgorithm->getLocalSignatureSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic256sha256; + asym_signatureAlgorithm->getRemoteSignatureSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic256sha256; + asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function + asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function + + 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(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic256sha256; + asym_encryptionAlgorithm->decrypt = + (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *)) + asym_decrypt_sp_basic256sha256; + asym_encryptionAlgorithm->getLocalKeyLength = NULL; // TODO: Write function + 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 + asym_encryptionAlgorithm->getRemotePlainTextBlockSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic256sha256; + + asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256sha256; + asymmetricModule->compareCertificateThumbprint = + asymmetricModule_compareCertificateThumbprint_sp_basic256sha256; + + /* SymmetricModule */ + symmetricModule->generateKey = sym_generateKey_sp_basic256sha256; + symmetricModule->generateNonce = sym_generateNonce_sp_basic256sha256; + + 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 (*)(const UA_SecurityPolicy *, 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; + 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; + sym_signatureAlgorithm->getRemoteKeyLength = + (size_t (*)(const UA_SecurityPolicy *, + 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->encrypt = + (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic256sha256; + sym_encryptionAlgorithm->decrypt = + (UA_StatusCode(*)(const UA_SecurityPolicy *, 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; + sym_encryptionAlgorithm->getRemotePlainTextBlockSize = + (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256sha256; + symmetricModule->secureChannelNonceLength = 32; + + // Use the same signature algorithm as the asymmetric component for certificate signing (see standard) + policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm; + + /* ChannelModule */ + channelModule->newContext = channelContext_newContext_sp_basic256sha256; + channelModule->deleteContext = (void (*)(void *)) + channelContext_deleteContext_sp_basic256sha256; + + channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymEncryptingKey_sp_basic256sha256; + channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymSigningKey_sp_basic256sha256; + channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setLocalSymIv_sp_basic256sha256; + + channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymEncryptingKey_sp_basic256sha256; + channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymSigningKey_sp_basic256sha256; + channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *)) + channelContext_setRemoteSymIv_sp_basic256sha256; + + channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *)) + channelContext_compareCertificate_sp_basic256sha256; + + policy->deleteMembers = deleteMembers_sp_basic256sha256; + + return policyContext_newContext_sp_basic256sha256(policy, localPrivateKey); +} + +#endif /* UA_ENABLE_ENCRYPTION */ |